php小編柚子在使用Go語言開發過程中,可能會遇到一些問題,其中之一就是在封閉的通道上發送數據時出現了問題。這個問題可能會導致通道的阻塞和程序的停滯,影響整個應用的運行。在解決這個問題之前,我們首先需要了解什么是封閉通道,以及為什么在封閉通道上發送數據會出現問題。接下來,我們將深入探討這個問題,并提供解決方案來修復和優化我們的Go應用程序。
問題內容
我收到一個致命錯誤:“在關閉的通道上發送”,有時我運行此代碼,我嘗試了多種解決方案,但沒有一個有效,這是代碼的表示,易于理解且易于使用測試:
CB14CE50B218D8EAB916B15CD95527D5
我想要的是啟動請求函數n次并獲取第一個完成的請求,然后關閉通道并且不要向通道發送更多請求,如果沒有一個請求成功完成,則等待所有goroutines完成.
我想發生這種情況是因為兩個或多個 goroutine 同時檢查通道是否關閉,并且兩個都嘗試在通道中寫入,這會導致致命錯誤。
錯誤:
goroutine 19 [running]: main.request(0xc00000a028, 0xc00000a030, 0x0?) C:/test/main.go:49 +0x135 created by main.main C:/test/main.go:17 +0xd3 panic: send on closed channel
登錄后復制
誰能解釋一下為什么會發生這種情況?
提前致謝
解決方法
問題是接收 goroutine (main
) 過早關閉 outputCh
。其他一些 goroutine 仍然可以嘗試在其上發送。
這是另一種方法:
package main import ( "fmt" "math/rand" "sync" "time" ) func main() { var wg sync.WaitGroup output := make(chan string) stop := make(chan bool) done := make(chan bool) for i := 0; i < 20; i++ { wg.Add(1) go request(output, stop, &wg) } go func() { wg.Wait() done <- true }() firstOutput := <-output fmt.Println("output:", firstOutput) fmt.Println("closing the stop channel") close(stop) <-done fmt.Println("end of main") } func request(output chan string, stop chan bool, wg *sync.WaitGroup) { defer wg.Done() fmt.Println("request started") time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond) select { case output <- "test": fmt.Println("output sent") case <-stop: fmt.Println("stop channel is closed") } }
登錄后復制