package mainimport ( "fmt" "runtime" "sync" "time")// Possible worker states.const ( Stopped = 0 Paused = 1 Running = 2)// Maximum number of workers.const WorkerCount = 1000func main() { // Launch workers. var wg sync.WaitGroup wg.Add(WorkerCount + 1) workers := make([]chan int, WorkerCount) for i := range workers { workers[i] = make(chan int) go func(i int) { worker(i, workers[i]) wg.Done() }(i) } // Launch controller routine. go func() { controller(workers) wg.Done() }() // Wait for all goroutines to finish. wg.Wait()}func worker(id int, ws <-chan int) { state := Paused // Begin in the paused state. for { select { case state = <-ws: switch state { case Stopped: fmt.Printf("Worker %d: Stopped\n", id) return case Running: fmt.Printf("Worker %d: Running\n", id) case Paused: fmt.Printf("Worker %d: Paused\n", id) } default: // We use runtime.Gosched() to prevent a deadlock in this case. // It will not be needed of work is performed here which yields // to the scheduler. runtime.Gosched() if state == Paused { break } // Do actual work here. } }}但是這段代碼也有一個問題:如果你想在退出workers時刪除一個工作通道,worker()就會發(fā)生死鎖。如果你close(workers[i]),下次控制器寫入它會導(dǎo)致恐慌,因為 go 無法寫入關(guān)閉的通道。如果你使用一些互斥鎖來保護它,那么它會被卡住,workers[i] <- Running因為worker它沒有從通道讀取任何東西,寫操作會被阻塞,互斥鎖會導(dǎo)致死鎖。作為變通方法,您還可以為通道提供更大的緩沖區(qū),但這還不夠好。所以我認(rèn)為解決這個問題的最好方法是worker()退出時關(guān)閉通道,如果控制器發(fā)現(xiàn)通道關(guān)閉,它會跳過它并且什么也不做。但是在這種情況下,我找不到如何檢查通道是否已關(guān)閉。如果我嘗試讀取控制器中的通道,則控制器可能被阻塞。所以我現(xiàn)在很困惑。PS:恢復(fù)引發(fā)的恐慌是我嘗試過的,但它會關(guān)閉引發(fā)恐慌的 goroutine。在這種情況下,它將是控制器,所以它沒有用。盡管如此,我認(rèn)為 Go 團隊在下一個版本的 Go 中實現(xiàn)這個功能是有用的。
3 回答

ABOUTYOU
TA貢獻(xiàn)1812條經(jīng)驗 獲得超5個贊
以一種駭人聽聞的方式,可以通過恢復(fù)引發(fā)的恐慌來為試圖寫入的通道完成。但是您無法在不讀取的情況下檢查讀取通道是否已關(guān)閉。
要么你會
最終從中讀取“真”值 (
v <- c
)讀取“真”值和“未關(guān)閉”指標(biāo) (
v, ok <- c
)讀取零值和“關(guān)閉”指示器 (
v, ok <- c
)將永遠(yuǎn)阻塞在通道中讀取 (
v <- c
)
只有最后一個在技術(shù)上不會從通道中讀取,但這沒什么用。

三國紛爭
TA貢獻(xiàn)1804條經(jīng)驗 獲得超7個贊
沒有辦法編寫一個安全的應(yīng)用程序,您需要知道一個通道是否打開而不與它交互。
做你想做的事情的最好方法是使用兩個渠道——一個用于工作,一個用于表示改變狀態(tài)的愿望(以及完成狀態(tài)改變,如果這很重要)。
渠道便宜。復(fù)雜的設(shè)計重載語義不是。
[還]
<-time.After(1e9)
是一種非常令人困惑且不明顯的寫作方式
time.Sleep(time.Second)
保持簡單,每個人(包括你)都能理解它們。
- 3 回答
- 0 關(guān)注
- 224 瀏覽
添加回答
舉報
0/150
提交
取消