3 回答

TA貢獻(xiàn)1775條經(jīng)驗(yàn) 獲得超11個(gè)贊
所以,讓我們看看你的源代碼中到底發(fā)生了什么。你有兩個(gè)goroutine(不止兩個(gè),但我們將專注于顯式的),main和readFromChannel.
讓我們看看有什么readFromChannel作用:
if channel `c` is not empty before `ti` has expired, print its contents and return, after signalling its completion to wait group.
if `ti` has expired before `c` is not empty, print "TIMED OUT" and return, after signalling its completion to wait group.
現(xiàn)在主要:
adds to waitgroup
make a channel `c`
start a goroutine `readFromChannel`
sleep for 5 seconds
send 10 to channel `c`
call wait for waitgroup
現(xiàn)在,讓我們同時(shí)執(zhí)行您的代碼的執(zhí)行流程(您的代碼可能/可能不會(huì)每次都按此順序執(zhí)行,請(qǐng)記住這一點(diǎn))
1) wg.Add(1)
2) c := make(chan int)
3) go readFromChannel(c, time.After(time.Duration(2)*time.Second))
#timer ti starts#
4) time.Sleep(time.Duration(5) * time.Second)
#MAIN Goroutine begins sleep
#timer ti expires#
5) case <-ti:
6) fmt.Println("TIMED OUT")
7) wg.Done()
# readFromChannel Goroutine returns #
#MAIN Goroutine exits sleep#
8) c<-10
9) ......#DEADLOCK#
現(xiàn)在你可以猜到為什么會(huì)出現(xiàn)死鎖。在進(jìn)行中,非緩沖通道將阻塞,直到通道的另一端發(fā)生某些事情,無論您是發(fā)送還是接收。所以c <- 10會(huì)阻塞,直到從 的另一端讀取某些內(nèi)容c,但是您為此擁有的 goroutine 已在 2 秒前從圖片中刪除。因此,c永遠(yuǎn)阻塞,并且由于main是最后一個(gè) goroutine,你會(huì)得到一個(gè)死鎖。
如何預(yù)防?使用頻道時(shí),請(qǐng)確保receive在頻道的另一端始終有一個(gè)send.
在這種情況下使用緩沖通道可以作為一種快速修復(fù),但可能會(huì)在更大的存儲(chǔ)庫(kù)中引發(fā)潛在的陷阱。例如,假設(shè)您c隨后寫入了更多數(shù)據(jù)并go readFromChannel(c, time.After(time.Duration(2)*time.Second))再次運(yùn)行。你可能會(huì)看到:
Read D1
Read D2
或者
TIMED OUT
Read D1
完全基于機(jī)會(huì)。這可能不是您想要的行為。
以下是我解決死鎖的方法:
func main() {
wg.Add(1)
c := make(chan int)
go readFromChannel(c, time.After(time.Duration(2)*time.Second))
time.Sleep(time.Duration(5) * time.Second)
c <- 10
wg.Wait()
}
func readFromChannel(c chan int, ti <-chan time.Time) {
// the forloop will run forever
loop: // **
for {
select {
case x := <-c:
fmt.Println("Read", x)
break loop // breaks out of the for loop and the select **
case <-ti:
fmt.Println("TIMED OUT")
}
}
wg.Done()
}

TA貢獻(xiàn)1848條經(jīng)驗(yàn) 獲得超10個(gè)贊
你有一個(gè)無緩沖的頻道。根據(jù)文檔:
如果通道沒有緩沖,發(fā)送方會(huì)阻塞,直到接收方收到該值。如果通道有緩沖區(qū),發(fā)送方只會(huì)阻塞,直到值被復(fù)制到緩沖區(qū)
通過將通道更改為緩沖,我們可以避免死鎖。
c := make(chan int, 10) // holds 10 ints
我還建議閱讀https://golang.org/doc/effective_go.html#channels,里面有一些與頻道相關(guān)的好東西。

TA貢獻(xiàn)1802條經(jīng)驗(yàn) 獲得超10個(gè)贊
這是一個(gè)較老的問題,但我自己正在深入學(xué)習(xí)渠道并在這里找到了這個(gè)。
我認(rèn)為您只需要在完成發(fā)送后關(guān)閉頻道嗎?
代碼:
func main() {
wg.Add(1)
c := make(chan int)
go readFromChannel(c, time.After(time.Duration(2)*time.Second))
time.Sleep(time.Duration(5) * time.Second)
c <- 10
close(c) // <- CLOSE IT HERE
wg.Wait()
}
- 3 回答
- 0 關(guān)注
- 159 瀏覽
添加回答
舉報(bào)