php小編柚子在這篇文章中將解答一個(gè)常見(jiàn)問(wèn)題:“為什么Go Channel的緩沖區(qū)不能正確限制寫(xiě)入/讀取?”在Go語(yǔ)言中,Channel是一種用于協(xié)程之間通信的機(jī)制。當(dāng)我們使用帶有緩沖區(qū)的Channel時(shí),期望能夠通過(guò)限制寫(xiě)入或讀取操作的數(shù)量來(lái)控制程序的行為。然而,實(shí)際上,Channel的緩沖區(qū)并不能直接限制寫(xiě)入/讀取操作的數(shù)量。下面將詳細(xì)闡述這個(gè)問(wèn)題的原因和解決方案。
問(wèn)題內(nèi)容
我正在嘗試使用通道在兩個(gè) go 例程之間進(jìn)行通信。首先,我創(chuàng)建了整數(shù)通道,然后將其作為參數(shù)傳遞給 go 例程,該例程打印從 0 到 10 的數(shù)字序列。這些程序的輸出沒(méi)有意義。
這是主要代碼:
func worker(identifier string, ch chan<- int) { fmt.printf("entering worker %s\n", identifier) for i := 0; i < 10; i++ { fmt.printf("writing %d\n", i) ch <- i } fmt.printf("exiting worker %s\n", identifier) close(ch) } func main() { ch := make(chan int) go worker("1", ch) for v := range ch { fmt.printf("reading %d\n", v) } }
登錄后復(fù)制
對(duì)于該代碼執(zhí)行,我得到了以下輸出:
entering worker 1 writing 0 writing 1 reading 0 reading 1 writing 2 writing 3 reading 2 reading 3 writing 4 writing 5 reading 4 reading 5 writing 6 writing 7 reading 6 reading 7 writing 8 writing 9 reading 8 reading 9 exiting worker 1
登錄后復(fù)制
請(qǐng)注意,有兩次寫(xiě)入執(zhí)行,然后是兩次讀取執(zhí)行。
后來(lái),我設(shè)置了一個(gè)緩沖區(qū)大小來(lái)實(shí)現(xiàn)如下功能:
func main() { ch := make(chan int, 3) // <= buffer go worker("1", ch) for v := range ch { fmt.printf("reading %d\n", v) } }
登錄后復(fù)制
然后,得到以下輸出:
Entering worker 1 Writing 0 Writing 1 Writing 2 Writing 3 Writing 4 Reading 0 Reading 1 Reading 2 Reading 3 Reading 4 Writing 5 Writing 6 Writing 7 Writing 8 Writing 9 Reading 5 Reading 6 Reading 7 Reading 8 Reading 9 Exiting worker 1
登錄后復(fù)制
請(qǐng)注意,現(xiàn)在我們有 5 個(gè)寫(xiě)入執(zhí)行,然后有 5 個(gè)讀取執(zhí)行。
一旦我們有了代碼和輸出,最后一個(gè)問(wèn)題就來(lái)了:為什么這些執(zhí)行的行為是這樣的?首先,它不是應(yīng)該每次只讀取和寫(xiě)入一個(gè)數(shù)字嗎?除此之外,為什么第二次執(zhí)行每次讀取和寫(xiě)入 5 個(gè)數(shù)字而不是 3 個(gè)(因?yàn)檫@是緩沖區(qū)大小)?
解決方法
當(dāng)打印消息時(shí)以及何時(shí)從通道讀取或?qū)懭霐?shù)字時(shí),您會(huì)混淆。
當(dāng)寫(xiě)入發(fā)生時(shí),不會(huì)發(fā)生“寫(xiě)入”消息。它們發(fā)生在寫(xiě)入之間的某個(gè)時(shí)刻。同樣,“正在閱讀”消息發(fā)生在讀取之間的某個(gè)時(shí)刻。
這是安排第一個(gè)代碼片段的一種方法,它會(huì)產(chǎn)生顯示的輸出:
主要嘗試讀取,然后阻塞。
工作人員打印“Writing 0”。
Worker 寫(xiě)入 0,main 讀取。
工人打印“Writing 1”。
工作線程嘗試寫(xiě)入 1,但被阻止。
主要打印“Reading 0”。
主要內(nèi)容為 1。
主要印刷品“閱讀1”。
主要嘗試讀取,然后阻塞。
Control 像這樣在 main 和 Worker 之間不斷傳遞,每個(gè)在阻塞之前打印 2 條消息。
同樣,您的第二個(gè)片段也可以這樣安排:
主要嘗試讀取,然后阻塞。
Worker 打印“Writing 0”,并將 0 直接發(fā)送到 main。
Worker 打印“Writing 1”,并緩沖 1。
Worker 打印“Writing 2”,并緩沖 2。
Worker 打印“Writing 3”,并緩沖 3。
工作線程打印“Writing 4”,并阻止嘗試發(fā)送 4。
main 完成被阻塞的讀取,并打印“Reading 0”。
main 讀取緩沖的 1,并打印“Reading 1”。
main 讀取緩沖的 2,并打印“Reading 2”。
main 讀取緩沖的 3,并打印“Reading 3”。
main 讀取 Worker 被阻塞的 4,并打印“Reading 4”。
主要嘗試讀取,然后阻塞。
執(zhí)行返回到 Worker…