Buffered Channel Deadlock'ları: Neden Goroutin Donuyor

Go'da buffered channel kullanırken en sık karşılaşılan sorun, goroutinin aniden durup hiç devam etmemesidir. Bunun nedeni çoğu zaman channel deadlock'ıdır. Buffered channel'ın kapasitesi dolduktan sonra ne olduğunu anlamak bu sorunun anahtarıdır.

Buffered channel, tanımlandığında belirtilen kapasite kadar veriyi hafızada tutabilir. Örneğin ch:= make(chan int, 2) komutu 2 elemanlık bir buffer oluşturur. Kanal doluğunda, gönderen goroutin alıcının veri almasını bekler. Alıcı yoksa veya alıcı yeterince hızlı değilse, gönderen goroutin kalıcı olarak bloke edilir.

Deadlock oluştuğunda program asılı kalır. Bunu görmek için şu örneği incele:

1package main
2import "fmt"
3
4func main() {
5ch:= make(chan int, 2)
6ch <- 1
7ch <- 2
8ch <- 3 // Deadlock! Buffer dolu, alıcı yok
9}

Çıktı: fatal error: all goroutines are asleep - deadlock!

Sorun şu: channel'a 3 eleman göndermek istiyoruz ama buffer sadece 2 tutabiliyor. Üçüncü gönderimi kabul edecek yer yok ve alıcı olmadığı için program donuyor.

Reklam · TEST
AdSense Test ReklamıYazı arası (gönderi içi) · Yazı arası

Çözüm üç yoldur. Birinci, alıcı goroutin başlatmak:

1package main
2import "fmt"
3
4func main() {
5ch:= make(chan int, 2)
6
7go func() {
8for val:= range ch {
9fmt.Println("Alınan:", val)
10}
11}()
12
13ch <- 1
14ch <- 2
15ch <- 3
16close(ch)
17}

Çıktı: Alınan: 1, Alınan: 2, Alınan: 3

İkinci yol, buffer kapasitesini artırmak:

1ch:= make(chan int, 3)

Üçüncü yol, select ile timeout eklemek:

1select {
2case ch <- 3:
3fmt.Println("Gönderildi")
4case <-time.After(1 * time.Second):
5fmt.Println("Timeout: Gönderme başarısız")
6}

Buffered channel deadlock'ını önlemek için: alıcı goroutin her zaman hazır tutun, buffer kapasitesini doğru hesaplayın ve yoğun işlemlerde select ile timeout kullanın.

Reklam · TEST
AdSense Test ReklamıGönderi altı · Görüntülü
konu hakkında tepkinizi verebilirsiniz