【问题标题】:Concurrency and Passing by value in goGo中的并发和传值
【发布时间】:2020-11-09 17:47:14
【问题描述】:

我在 go 中有一个代码 sn-p:

for _, u := range urls {
        done.Add(1)
        u2 := u
        go func() {
            defer done.Done()
            ConcurrentMutex(u2, fetcher, f)
        }()
        //go func(u string) {
        //  defer done.Done()
        //  ConcurrentMutex(u, fetcher, f)
        //}(u)
    }

为了让ConcurrentMutex 看到不同的u 值,需要使用中间变量u2 或使用注释掉的代码。如果我只是这样做:

for _, u := range urls {
        done.Add(1)
        go func() {
            defer done.Done()
            ConcurrentMutex(u, fetcher, f)
        }()
    }

我很困惑为什么它的行为与注释掉的代码的行为不同。 Go 是按值传递的,当我将u 传递给ConcurrentMutex 时,它不应该只是复制当前u 的值,从而不受以后对u 所做的更改吗?

【问题讨论】:

  • 是的,参数总是按值传递,但你不知道何时评估参数,因为它同时发生在循环中。对于这么短的循环,很可能(但不能保证!)所有 ConcurrentMutex 调用都发生在循环长时间完成之后。

标签: go concurrency


【解决方案1】:

u 传递给 ConcurrentMutex 的那一刻,将创建并传递它的副本。但是,当 goroutine 传递 u 的值时,它可能与 goroutine 启动时处于活动状态的 u 值不同。也就是说,这个执行是可能的:for循环以u值启动goroutine,然后for循环用序列中的下一项覆盖u值,然后goroutine调用ConcurrentMutex新的u 值,跳过之前的u 值。

【讨论】:

  • 谢谢你,这是有道理的。但是为什么注释掉的代码不会成为问题呢?
  • 在注释掉的代码中,u 的副本被传递给函数。即使 for 循环中的 u 发生变化,函数中的副本也不会发生变化。如果您将 &u 传递给获取指针的函数,这将失败。
猜你喜欢
  • 2019-05-09
  • 2012-01-04
  • 2019-10-14
  • 1970-01-01
  • 2014-01-11
  • 2011-06-06
  • 1970-01-01
  • 1970-01-01
  • 2015-07-09
相关资源
最近更新 更多