Dalam program Golang, saluran memudahkan komunikasi antara goroutine. Walau bagaimanapun, penyalahgunaan saluran boleh menyebabkan kebuntuan, seperti yang ditunjukkan dalam kod di bawah:
pakej utama
import (
"fmt" "sync"
)
func push(c chan int, wg sync.WaitGroup) {
for i := 0; i < 5; i++ { c <- i } wg.Done()
}
func pull(c chan int, wg sync.WaitGroup) {
for i := 0; i < 5; i++ { result, ok := <-c fmt.Println(result, ok) } wg.Done()
}
func main() {
var wg sync.WaitGroup wg.Add(2) c := make(chan int) go push(c, wg) go pull(c, wg) wg.Wait() // Block the main thread until goroutines complete
}
Apabila menjalankan program ini, anda mungkin menghadapi ralat berikut:
fatal error: all goroutines are asleep - deadlock!
Untuk memahami sebab kebuntuan ini berlaku, mari kita teliti kod:
Masalahnya terletak pada cara WaitGroup dihantar ke goroutine. Apabila nilai diluluskan tanpa ampersand (&), ia diluluskan oleh nilai dan bukan dengan rujukan. Dalam kes ini, salinan WaitGroup dibuat untuk setiap goroutine.
Akibatnya, apabila setiap goroutine memanggil wg.Done(), ia mengubah suai salinan tempatan WaitGroup. Memandangkan utas utama menunggu sehingga wg menunjukkan bahawa semua goroutine telah selesai, ia menunggu selama-lamanya kerana kedua-dua goroutine tidak mengemas kini WaitGroup yang asal. Ini membawa kepada kebuntuan.
Untuk menyelesaikan isu ini, kita perlu lulus WaitGroup melalui rujukan. Ini memastikan bahawa kedua-dua goroutine mengubah suai contoh WaitGroup yang sama dan menandakan penyempurnaannya kepada urutan utama dengan betul.
Berikut ialah versi semakan kod dengan pembetulan:
pakej utama
import (
"fmt" "sync"
)
func push(c chan int, wg *sync.WaitGroup) {
for i := 0; i < 5; i++ { c <- i } wg.Done()
}
func pull(c chan int, wg *sync.WaitGroup) {
for i := 0; i < 5; i++ { result, ok := <-c fmt.Println(result, ok) } wg.Done()
}
func main() {
var wg sync.WaitGroup wg.Add(2) c := make(chan int) go push(c, &wg) // Pass the WaitGroup by reference using the ampersand go pull(c, &wg) // Pass the WaitGroup by reference using the ampersand wg.Wait()
}
Dengan menghantar WaitGroup melalui rujukan, kami memastikan bahawa urutan utama boleh menentukan dengan betul apabila kedua-dua gorout telah menyelesaikan tugas mereka, sekali gus mengelakkan kebuntuan.
Atas ialah kandungan terperinci Mengapakah menghantar WaitGroup mengikut nilai dalam Go membawa kepada kebuntuan, dan bagaimanakah ia boleh diselesaikan?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!