Rumah >pembangunan bahagian belakang >Golang >Mengapa Saluran Tidak Dibuffer dalam Pergi Menyebabkan Kebuntuan?

Mengapa Saluran Tidak Dibuffer dalam Pergi Menyebabkan Kebuntuan?

Mary-Kate Olsen
Mary-Kate Olsenasal
2024-12-21 17:31:11227semak imbas

Why Do Unbuffered Channels in Go Cause Deadlocks?

Kebuntuan dalam Saluran Tidak Dibuffer di Goroutines

Dalam model konkurensi Go, saluran yang tidak ditimbal boleh membawa kepada kebuntuan yang tidak dijangka. Mari kita selidiki sebab perkara ini berlaku dan terokai penyelesaian alternatif.

Pertimbangkan coretan kod berikut:

package main

import "fmt"

func main() {
    c := make(chan int)    
    c <- 1   
    fmt.Println(<-c)
}

Kod ini nampaknya melakukan operasi hantar dan terima yang mudah pada saluran yang tidak ditimbal. Walau bagaimanapun, apabila dijalankan, ia mengakibatkan jalan buntu dengan ralat berikut:

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.main()
    /home/tarrsalah/src/go/src/github.com/tarrsalah/tour.golang.org/65.go:8 +0x52
exit status 2

Untuk memahami sebab kebuntuan ini berlaku, kita mesti terlebih dahulu memahami kelakuan saluran tidak buffer.

Menyelidiki Saluran Tidak Dibuffer

Seperti yang didokumenkan dalam dokumentasi rasmi Go, "Jika saluran itu unbuffered, penghantar menyekat sehingga penerima telah menerima nilai Jika saluran mempunyai penimbal, penghantar menyekat hanya sehingga nilai telah disalin ke penimbal, ini bermakna menunggu sehingga beberapa penerima telah mendapatkan nilai ."

Dalam istilah yang lebih mudah:

  1. Saluran yang tidak ditimbal dianggap selama-lamanya penuh.
  2. Menghantar data ke saluran tidak buffer menyekat penghantar sehingga goroutine lain mendapatkan semula nilai.

Senario Kebuntuan

Dalam memberikan coretan kod, operasi c <- 1 blok kerana saluran tidak dibuffer dan tiada yang lain goroutine wujud untuk menerima nilai yang dihantar. Akibatnya, program menemui jalan buntu.

Memecah Kebuntuan

Untuk menyelesaikan kebuntuan, kita boleh sama ada:

  1. Gunakan a Saluran Penimbalan: Dengan mencipta saluran penimbal (cth., c := make(chan int, 1)), kami memperuntukkan penimbal kecil di mana goroutin penghantar boleh meletakkan nilai buat sementara waktu sebelum penerima sedia.

ATAU

  1. Perkenalkan Goroutine Penerima : Kami boleh memperkenalkan goroutine yang berasingan untuk mengendalikan penerimaan data daripada saluran. Ini memastikan pengguna sentiasa bersedia untuk mendapatkan semula nilai yang dihantar.

Contoh dengan Goroutine Penerima:

package main

import "fmt"

func main() {
    c := make(chan int)    
    go func() {
        fmt.Println("received:", <-c)
    }()
    c <- 1   
}

Di sini, goroutine yang dibuat dengan go func() {...} akan terus menunggu untuk menerima nilai daripada saluran. Dengan memperkenalkan goroutine penerima ini, kebuntuan dapat dicegah.

Kesimpulannya, menggunakan saluran yang tidak dibuffer dalam goroutine yang sama tanpa mekanisme penerimaan yang khusus boleh menyebabkan kebuntuan. Untuk mengelakkan perkara ini, pertimbangkan untuk menggunakan saluran penimbal atau memperkenalkan goroutin penerimaan yang berasingan untuk memastikan pemindahan data yang betul antara gorouti serentak.

Atas ialah kandungan terperinci Mengapa Saluran Tidak Dibuffer dalam Pergi Menyebabkan Kebuntuan?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn