[英]How to use channels in go?
我有一個函數,它接受一個 int 數組並將它們轉儲到一個通道中。
func Dump(a []int, ch chan int) {
for i := range a {
ch <- i
}
close(ch)
}
這個主要不建立:
func main() {
ch := make(chan int)
arr := []int{1, 2, 3, 4, 5}
Dump(arr, ch)
for i := range ch {
fmt.Printf("Got %v\n", i)
}
}
拋出這個錯誤:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.Dump(0xc000078f48, 0x5, 0x5, 0xc00006e060)
/Users/300041738/go-workspace/src/test.go:7 +0x43
main.main()
/Users/300041738/go-workspace/src/test.go:15 +0x9b
exit status 2
但是,這會構建:
func main() {
ch := make(chan int)
arr := []int{1, 2, 3, 4, 5}
go Dump(arr, ch)
for i := range ch {
fmt.Printf("Got %v\n", i)
}
}
為什么我必須在 Dump 前面寫 go? 我不想異步轉儲數組的內容。
通道有緩沖區。 默認情況下,緩沖區的大小為 0。換句話說,如果一個元素要插入到一個非緩沖的通道中,插入的 goroutine 將停止,直到另一個 goroutine 從通道中檢索到值。
所以為了好玩,試試這個:
import "fmt"
func Dump(a []int, ch chan int) {
for i := range a {
ch <- i
}
close(ch)
}
func main() {
arr := []int{1, 2, 3, 4, 5}
ch := make(chan int, len(arr)) //specify channel buffer length equal to arr size
Dump(arr, ch)
for {
i, ok := <- ch
if ok {
fmt.Println("received a number !", i)
} else {
fmt.Println("channel is closed, we're done here")
}
}
}
解除鎖定是因為您的主要 goroutine 正在嘗試寫入通道,但沒有人從中讀取。 您不需要在此處使用緩沖通道。
go中有流水線的概念。 您的Dump
函數基本上就像這里的管道源。 您可以將Dump
函數修改為如下所示:
func Dump(a []int) chan int {
ch := make(chan int)
go func() {
for i := range a {
ch <- i
}
close(ch)
}()
return ch
}
請注意,我現在正在一個單獨的 go 例程中寫入通道。
問題的根源 - 當您寫入無緩沖通道時,它會被鎖定,直到有人從通道中讀取值。 對於無緩沖通道 - 在每次寫入操作后,您必須執行一次讀取操作。 否則你的第二個寫操作將被鎖定,直到有人讀取第一個值。 在你的第一個例子中,它永遠不會發生。
為了顯示:
Dump()
函數for
循環的第一次迭代i
值寫入通道for
循環的第二次迭代i
值寫入通道,但它鎖定,沒有人讀取第一個值。 添加 goroutine 用法時會發生這種情況( go Dump(arr, ch)
):
Dump()
函數for
循環的第一次迭代i
值寫入通道for
循環的第二次迭代i
值寫入通道,但它鎖定,沒有人讀取第一個值。Dump()
),但我們有主 goroutine 和 go scheduler 將控制切換到主 goroutine。for i := range ch
。 它終於讀取了第一個值!Dump()
goroutine 已解鎖,可以寫入第二個值。 請注意,執行的確切順序可能會有所不同(基於 go 調度程序的邏輯)。 要使用它,您可以使用go Dump(arr, ch)
將 print 添加到Dump()
函數中:
func Dump(a []int, ch chan int) {
for i := range a {
fmt.Printf("Write %v\n", i)
ch <- i
}
close(ch)
}
您將看到 Write 和 Got 消息會混合在一起。
很難為您的答案提供解決方案,因為它是一個沙箱示例,實際上不需要該通道。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.