Apabila panggilan fungsi yang mengisi saluran tidak dibenamkan dalam Goroutine, sebab kebuntuan berlaku adalah kerana operasi hantar dan terima saluran disekat. Jika fungsi yang mengisi saluran dipanggil dalam Goroutine utama, dan operasi pengisian tidak dimasukkan ke dalam Goroutine baharu untuk dijalankan di dalam fungsi, maka Goroutine utama akan menunggu saluran mempunyai ruang yang cukup untuk menerima data, dan operasi mengisi tidak dapat dilakukan, dengan itu Membawa kepada kebuntuan. Oleh itu, untuk mengelakkan kebuntuan, kita perlu menggunakan Goroutine untuk pelaksanaan serentak dalam operasi mengisi saluran bagi memastikan operasi pengisian dan operasi penerimaan dapat dilakukan pada masa yang sama.
Saya tahu tentang pilihan sync
包及其 waitgroup
dan saya tidak mahu menggunakannya untuk ujian ini. Saya sedang menguji semafor.
Jadi saya ada:
package main import ( "fmt" "os" "time" ) func main() { fmt.print("wassap") jobs := make(chan int) processstarted := make(chan struct{}, 1) processcompleted := make(chan struct{}, 1) createjobs(jobs) go func() { worker(jobs, processstarted, processcompleted) }() go func() { sync(processstarted, processcompleted) }() time.sleep(3600 * time.second) fmt.print("\nend of main...") interrupt := make(chan os.signal) <-interrupt } func createjobs(jobs chan<- int) { defer close(jobs) for i := 1; i < 20; i++ { jobs <- i } } func worker(jobs <-chan int, processstarted <-chan struct{}, processcompleted <-chan struct{}) { for { select { case i := <-jobs: fmt.printf("\nfetching job #%d from channel", i) time.sleep(2 * time.second) case <-processstarted: fmt.print("\nprocess started. waiting for it to be completed") <-processcompleted fmt.print("\nprocess completed") } } } func sync(processstarted chan<- struct{}, processcompleted chan<- struct{}) { // acquire semaphore. send signal to channel to indicate that it is busy processstarted <- struct{}{} for i := 1; i < 5; i++ { fmt.printf("\nprocessing %d", i) time.sleep(5 * time.second) } // release semaphore processcompleted <- struct{}{} }
Apa yang saya ingin uji adalah sangat mudah: Saya mempunyai createjobs
函数,其唯一目的是将元素添加到通道,在本例中是一个 int 通道。然后我有一个 worker
yang akan mengekstrak objek dari saluran itu dan tidur selama 2 saat sebelum mengekstrak elemen seterusnya.
Kini, terdapat juga fungsi penyegerakan. Satu-satunya tujuan fungsi ini adalah untuk mensimulasikan elemen worker
运行时启动的进程。如果此进程处于活动状态,则在 sync
结束时应停止处理 jobs
, itulah sebabnya saya mempunyai dua saluran, satu menunjukkan bahawa proses telah dimulakan dan satu lagi bahawa proses telah tamat.
Saya mendapat ralat berikut semasa menjalankan kod saya:
fatal error: all goroutines are asleep - deadlock!
Jika saya mengubah suai cara createjobs
dipanggil, bungkusnya dalam goroutine seperti ini:
go func() { createJobs(jobs) }()
Kemudian kod saya berjalan dengan betul.
Saya cuma nak faham kenapa ini berlaku. Apa yang saya maksudkan ialah: rutin main
sedang dilaksanakan dan kemudian ia memanggil main
例程正在执行,然后它调用 createjobs
(无换行),因此 main
例程应该被阻止,直到此调用结束。一旦 createjobs
结束,就说明通道中有元素了。 main
继续执行并启动其他 goroutine worker
和 sync
来完成它们的工作。在 main
(tanpa baris baharu), jadi rutin main
harus disekat sehingga panggilan ini tamat. Sebaik sahaja
utama
meneruskan pelaksanaan dan memulakan gorout lain pekerja
dan sync
untuk menyelesaikan kerja mereka. Sebelum utama
tamat, saya hanya menambah sleeper untuk memberi masa goroutine yang dibuat sebelum ini untuk disiapkan.
createjobs
发生在 goroutine 之外时会发生什么。
您将 jobs
声明为无缓冲通道,然后尝试将 20 个值同步推入其中。当您调用 createjobs(jobs)
Saya tidak meminta penyelesaian lain untuk masalah ini, saya cuma ingin tahu apa yang berlaku apabila
pekerjaan
sebagai saluran yang tidak ditimbal dan kemudian cuba menolak 20 nilai ke dalamnya secara serentak. Ini akan menyekat fungsi utama anda apabila anda memanggil . Tukar baris 13 kepada:
jobs := make(chan int, 20)
...akan menyelesaikan kebuntuan.
EDIT - Penjelasan diminta dalam ulasan:createjobs(jobs)
Satu analogi yang baik untuk saluran yang tidak dibuffer ialah paip, dalam kes ini prosesnya kelihatan seperti ini:
+------------------+ +------------+ +-------------+ | PRODUCER | | PIPE | | CONSUMER | | +---->| +----->| | | createJobs(jobs) | | unbuffered | | worker(...) | | | | channel | | | +------------------+ +------------+ +-------------+
dipanggil serentak dan belum ada pengguna yang sedang berjalan.
main()
Atas ialah kandungan terperinci Mengapakah kebuntuan berlaku apabila panggilan fungsi yang mengisi saluran tidak dibenamkan dalam Goroutine?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!