go中的并发和按值传递
我在go中有一个代码片段:go中的并发和按值传递,go,concurrency,Go,Concurrency,我在go中有一个代码片段: 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() /
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)
}
为了让concurrentutex
看到不同的u
值,需要使用中间变量u2
或使用注释掉的代码。如果我只是做:
for _, u := range urls {
done.Add(1)
go func() {
defer done.Done()
ConcurrentMutex(u, fetcher, f)
}()
}
我不明白为什么这个行为会与注释掉的代码的行为不同。Go是通过值传递的,当我将
u
传递给concurrentutex
时,它不应该只是复制当前u
的值,从而对以后对u
所做的更改免疫吗?u
传递给concurrentutex
的那一刻,它的副本将被创建并传递。但是,当goroutine传递u
的值时,它可能与goroutine启动时处于活动状态的u
值不同。也就是说,这种执行是可能的:for循环用u
值启动goroutine,然后for循环用序列中的下一项覆盖u
值,然后goroutine用新的u
值调用concurrentutex
,跳过上一个u
值。是,参数总是按值传递,但您不知道参数何时求值,因为它同时发生在循环中。对于如此短的循环,所有ConcurrentMutex调用都很可能(但不能保证!)在循环长时间结束后发生。谢谢,这很有意义。但是,对于注释掉的代码,这为什么不是一个问题呢?在注释掉的代码中,u
的副本被传递给函数。即使for循环中的u
in发生变化,函数中的副本也不会发生变化。如果将&u
传递给获取指针的函数,则此操作将失败。