go func() { defer wg.Done() for i := 0; i < n; i++ { ch <- i } }()
go func() {
defer wg.Done()
for i := 0; i < n; i++ {
ch <- i
}
}()
go func() { for i := 0; i < n; i++ { ch <- i } wg.Done() }()
wg.Done()
这两个代码是一样的吗?看起来是一样的,我看过这两篇文章。
nhaq1z211#
这两个似乎是相同的,可能有情况下,他们不是。这是因为如果函数出现异常,也会执行延迟函数。因此,例如,如果ch是一个封闭的通道,在封闭的通道上发送将死机(请参见未初始化的通道如何工作?),如果没有defer,则不会调用wg.Done()。如果是defer的话,就可以了。这对于另一个调用wg.Wait()的goroutine解除阻塞可能非常重要。另一个不同之处是,延迟函数及其参数在执行defer语句时进行计算,在本例中是在循环之前。如果wg变量将被修改,例如在第一次发送之后,具有defer的一个不会看到wg的新值,没有defer的一个会看到它在循环之后的评估。总而言之,在有意义的时候使用defer,即使您或其他人后来修改/扩展了代码,也不会忘记。举个例子,有人插入了一个条件return:
ch
defer
wg.Wait()
wg
return
go func() { defer wg.Done() for i := 0; i < n; i++ { ch <- i if i == 3 { return } }}()
if i == 3 {
使用defer,这不会是一个问题,wg.Wait()仍然会被调用。如果没有defer,就不会有。参见相关问题:在循环中释放延迟资源的正确方法?延迟调用的参数立即计算
1条答案
按热度按时间nhaq1z211#
这两个似乎是相同的,可能有情况下,他们不是。这是因为如果函数出现异常,也会执行延迟函数。
因此,例如,如果
ch
是一个封闭的通道,在封闭的通道上发送将死机(请参见未初始化的通道如何工作?),如果没有defer
,则不会调用wg.Done()
。如果是defer
的话,就可以了。这对于另一个调用wg.Wait()
的goroutine解除阻塞可能非常重要。另一个不同之处是,延迟函数及其参数在执行
defer
语句时进行计算,在本例中是在循环之前。如果wg
变量将被修改,例如在第一次发送之后,具有defer
的一个不会看到wg
的新值,没有defer
的一个会看到它在循环之后的评估。总而言之,在有意义的时候使用
defer
,即使您或其他人后来修改/扩展了代码,也不会忘记。举个例子,有人插入了一个条件return
:使用
defer
,这不会是一个问题,wg.Wait()
仍然会被调用。如果没有defer
,就不会有。参见相关问题:
在循环中释放延迟资源的正确方法?
延迟调用的参数立即计算