[英]golang buffer channel unexpected result
package main
import (
"time"
"runtime"
)
var c = make(chan int, 2)
func main() {
go worker(1)
for i := 0; i < 30; i++ {
go func() {
// k := i make a local copy not make any difference
c <- i
}()
}
time.Sleep(100* time.Second)
}
func worker(id int) {
for {
a := <-c
println(a, runtime.NumGoroutine())
time.Sleep(time.Second)
}
}
輸出是不可預測的,有時如下所示。
7 9
13 29
13 28
13 27
13 26
13 25
13 24
13 23
16 22
16 21
17 20
19 19
21 18
21 17
23 16
25 15
26 14
26 13
26 12
26 11
26 10
26 9
26 8
26 7
27 6
27 5
13 4
28 3
30 2
30 2
我知道發送方將在緩沖區通道已滿時阻止,並且當通道可用時發送方可以繼續。
輸出不是恆定的,因為不同的goroutine共享相同的局部變量i。 如果取消注釋行並將其移動到goruoutine調用之前,則會看到恆定輸出0-29。 更好的方法是將i變量移至goroutine函數參數。
規格中未指定喚醒順序。 您應該將其視為隨機的。
3是FIFO
1因為在for循環內創建的goroutine不一定按順序執行。 基礎的Go調度程序將隨機啟動一個(這是通道分配其值的方式)。 的,當然,所有的人都會生成,但他們(被安排)在點開始time.Sleep(...)
在main
被稱為(去調度是合作之一,像函數調用某些點這樣做,頻道操作等-例如this )
2直接使用頻道:
var (
c = make(chan int, 2)
wg = &sync.WaitGroup{}
)
func main() {
wg.Add(1)
go worker(1)
wg.Add(1)
go func() {
defer wg.Done()
for i := 0; i < 30; i++ {
c <- i
}
close(c)
}()
wg.Wait()
}
func worker(id int) {
defer wg.Done()
for a := range c {
println(a, runtime.NumGoroutine())
time.Sleep(time.Second)
}
}
關於傳遞for
循環變量; 您幾乎正確地完成了操作。 您只需要在goroutine之外添加以下代碼以創建本地閉包:
var (
wg = &sync.WaitGroup{}
)
func main() {
for i := 0; i < 3; i++ {
localClosure := i // <- this line
wg.Add(1)
go func() {
defer wg.Done()
println(localClosure)
}()
}
wg.Wait()
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.