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)
}
}
the output is unpredictable, sometimes like below.
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
I know sender will block if the buffer channel is full, and when channel is available the sender can continue.
Output is not constant because different goroutines share same local variable i. If you uncomment your line and move it right before the goruoutine call, you'll see constant output 0-29. The better way is to move i variable to goroutine function arguments.
Wake up order is not specified in specs. You should consider it as a random one.
3 It is FIFO
1 Because the goroutines created inside the for loop will not necessarily execute sequentially. The underlying Go scheduler will start one randomly (it's how channels dispatch their values). Of-course all of them will get created, but they will (get scheduled to) start at the point time.Sleep(...)
in main
is called (Go scheduler is a cooperative one and does so on certain points like function calls, channel ops, etc - for example this)
2 Use the channel directly:
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)
}
}
About passing a for
loop variable; you've done it almost correctly. You just have to put the line to create the local closure, outside the 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()
}