Go のデッドロック: 「すべての go ルーチンがスリープ状態です」
提供されたコードを実行すると、非同期実行モデルが原因でデッドロックが発生しますゴルーチンを使用します。この問題は、トラックがチャネルに送信される前に UnloadTrucks 関数が呼び出されたときに発生します。これにより、チャネルが空のままになり、送信側のゴルーチンが ch
解決策: WaitGroup を使用してチャネルを閉じる
デッドロックを解決するには、すべてのゴルーチンがトラックの送信を完了した後にチャネル ch を閉じることができます。これは、保留中のゴルーチンの数を追跡する同期プリミティブである WaitGroup を導入することで実現できます。
go func() { wg.Wait() close(ch) }()
このゴルーチンは、他のすべてのゴルーチンが (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 中国語 Web サイトの他の関連記事を参照してください。