在循环中开启 goroutine,传递参数最好通过变量赋值,而不是利用函数闭包; 因为 goroutine 最终读取变量的时间是不确定的,从而 goroutine 中获取到变量的值不一定符合最初的预期。
错误使用
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
package main
import (
"fmt"
"sync"
)
func main() {
wg := sync.WaitGroup{}
for i := 0; i < 10; i++ {
var fn = func() int {
return i
}
fmt.Println(fn())
wg.Add(1)
go func() {
defer wg.Done()
fmt.Println("routine ", fn())
}()
}
wg.Wait()
}
|
输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
0
1
2
3
4
5
6
7
8
9
routine 10
routine 10
routine 10
routine 10
routine 10
routine 10
routine 10
routine 10
routine 10
routine 10
|
正确使用
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
package main
import (
"fmt"
"sync"
)
func main() {
wg := sync.WaitGroup{}
for i := 0; i < 10; i++ {
var fn = func(i int) int {
return i
}
fmt.Println(fn(i))
wg.Add(1)
go func(i int) {
defer wg.Done()
fmt.Println("routine ", fn(i))
}(i)
}
wg.Wait()
}
|
输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
0
1
2
3
4
5
6
7
8
9
routine 9
routine 5
routine 6
routine 7
routine 8
routine 3
routine 1
routine 0
routine 2
routine 4
|
现象分析
- 函数闭包没有问题, 变量
i
没有被释放
- for 循环结束时, 变量
i
的值为 10
- 在
错误使用
中, 所有 goroutine 都使用同一个 i
变量, goroutine 的执行时机决定了输出结果
- 在
正确使用
中, 所有 goroutine 使用值传递,无论 goroutine 是否启动, 变量已经被赋值