首页 >后端开发 >Golang >如何解决异步操作和空通道导致的Go死锁?

如何解决异步操作和空通道导致的Go死锁?

Barbara Streisand
Barbara Streisand原创
2024-12-11 18:04:12242浏览

How to Resolve Go Deadlocks Caused by Asynchronous Operations and Empty Channels?

Go 中的死锁:“所有 go 例程都在睡眠”

运行提供的代码时,由于其异步执行模型而发生死锁使用 goroutine。在将任何卡车发送到通道之前调用 UnloadTrucks 函数时,就会出现问题。这会导致通道保持空状态,导致发送者 goroutine 在 ch

解决方案:使用 WaitGroup 关闭通道

为了解决死锁,我们可以在所有 goroutine 发送完卡车后关闭通道 ch。这可以通过引入 WaitGroup 来实现,这是一个跟踪待处理 goroutine 数量的同步原语:

go func() {
    wg.Wait()
    close(ch)
}()

此 goroutine 会等待,直到所有其他 goroutine 完成其任务(由 Wait() 调用发出信号)。关闭通道。通过这样做,UnloadTrucks 函数能够在所有卡车发送完毕后正常退出。

修改后的代码:

package main

import (
    "fmt"
    "sync"
    "time"
)

type Item struct {
    name string
}

type Truck struct {
    Cargo []Item
    name  string
}

func UnloadTrucks(c chan Truck) {

    for t := range c {
        fmt.Printf("%s has %d items in cargo: %s\n", t.name, len(t.Cargo), t.Cargo[0].name)
    }

}

func main() {
    trucks := make([]Truck, 2)

    ch := make(chan Truck)

    var wg sync.WaitGroup
    for i, _ := range trucks {

        trucks[i].name = fmt.Sprintf("Truck %d", i+1)

        fmt.Printf("Building %s\n", trucks[i].name)
    }

    for t := range trucks {
        go func(tr Truck) {

            itm := Item{}
            itm.name = "Groceries"

            fmt.Printf("Loading %s\n", tr.name)
            tr.Cargo = append(tr.Cargo, itm)
            ch <- tr
            wg.Done()

        }(trucks[t])
        wg.Add(1)
    }

    time.Sleep(50 * time.Millisecond)
    fmt.Println("Unloading Trucks")
    UnloadTrucks(ch)

    fmt.Println("Done")
}

使用此修改后的代码,死锁被消除是因为 UnloadTrucks 函数保证在通道关闭之前接收到所有卡车。这可以确保所有 goroutine 正确完成其任务,并且程序运行不会出现任何意外中断。

以上是如何解决异步操作和空通道导致的Go死锁?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn