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
我知道如果缓冲区通道已满,发送方将阻止,当通道可用时,发送方可以继续。
答案 0 :(得分:2)
输出不是常数,因为不同的goroutine共享相同的局部变量i。如果取消注释你的线并在goruoutine调用之前移动它,你会看到常量输出0-29。更好的方法是将i变量移动到goroutine函数参数。
规格中未指定唤醒订单。你应该把它视为一个随机的。
答案 1 :(得分:0)
3是FIFO
1因为在for循环中创建的goroutine不一定按顺序执行。底层的Go调度程序将随机启动一个(这是通道调度其值的方式)。当然所有这些都将被创建,但它们将(调度)从time.Sleep(...)
中的main
开始被调用(Go调度程序是一个合作的,并且在某些点上执行此操作,如函数电话,频道操作等 - 例如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()
}