协程中参数直接使用,和传参的区别是什么,为什么会造成这种结果

参考解析

题目来源:字节跳动

作者:

协程中参数直接使用,和传参的区别是什么,为什么会造成这种结果

以一个例子说明

直接使用

  1. func main() {
  2. wg := sync.WaitGroup{}
  3. for i := 0; i < 10; i++ {
  4. wg.Add(1)
  5. go func(ctx,func(ctx context.Context) {
  6. fmt.Println(i)
  7. wg.Done()
  8. })
  9. }
  10. wg.Wait()
  11. }

执行输出结果

10 10 10 10 10 10 10 10 10 10

传参使用

  1. func main() {
  2. wg := sync.WaitGroup{}
  3. for i := 0; i < 10; i++ {
  4. wg.Add(1)
  5. go func(ctx,func(ctx context.Context) {
  6. fmt.Println(i)
  7. wg.Done()
  8. })(i)
  9. }
  10. wg.Wait()
  11. }

执行输出结果

0 9 3 4 5 6 7 8 1 2

产生这种结果的原因是,对于一部协程来说,函数在执行异步执行注册时,该函数并未真正开始执行注册时只在goroutine的栈中保存了变量i的内存地址,而一旦开始执行函数时才会去读取变量i的值,而这时变量i的值已经自增到了10,改进的方案就是在注册异步执行函数的时候,把变量的值也一并传递获取,或者吧当前变量i的值赋值给一个不会改变的临时变量中,在函数中使用该临时变量而不是直接使用i