协程中参数直接使用,和传参的区别是什么,为什么会造成这种结果
参考解析
题目来源:字节跳动
作者:
协程中参数直接使用,和传参的区别是什么,为什么会造成这种结果
以一个例子说明
直接使用
func main() {
wg := sync.WaitGroup{}
for i := 0; i < 10; i++ {
wg.Add(1)
go func(ctx,func(ctx context.Context) {
fmt.Println(i)
wg.Done()
})
}
wg.Wait()
}
执行输出结果
10 10 10 10 10 10 10 10 10 10
传参使用
func main() {
wg := sync.WaitGroup{}
for i := 0; i < 10; i++ {
wg.Add(1)
go func(ctx,func(ctx context.Context) {
fmt.Println(i)
wg.Done()
})(i)
}
wg.Wait()
}
执行输出结果
0 9 3 4 5 6 7 8 1 2
产生这种结果的原因是,对于一部协程来说,函数在执行异步执行注册时,该函数并未真正开始执行注册时只在goroutine的栈中保存了变量i的内存地址,而一旦开始执行函数时才会去读取变量i的值,而这时变量i的值已经自增到了10,改进的方案就是在注册异步执行函数的时候,把变量的值也一并传递获取,或者吧当前变量i的值赋值给一个不会改变的临时变量中,在函数中使用该临时变量而不是直接使用i