Go语言 在这种情况下,我可以省略defer关键字吗?

shstlldc  于 12个月前  发布在  Go
关注(0)|答案(1)|浏览(111)
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()
    }()

这两个代码是一样的吗?看起来是一样的,我看过这两篇文章。

nhaq1z21

nhaq1z211#

这两个似乎是相同的,可能有情况下,他们不是。这是因为如果函数出现异常,也会执行延迟函数。
因此,例如,如果ch是一个封闭的通道,在封闭的通道上发送将死机(请参见未初始化的通道如何工作?),如果没有defer,则不会调用wg.Done()。如果是defer的话,就可以了。这对于另一个调用wg.Wait()的goroutine解除阻塞可能非常重要。
另一个不同之处是,延迟函数及其参数在执行defer语句时进行计算,在本例中是在循环之前。如果wg变量将被修改,例如在第一次发送之后,具有defer的一个不会看到wg的新值,没有defer的一个会看到它在循环之后的评估。
总而言之,在有意义的时候使用defer,即使您或其他人后来修改/扩展了代码,也不会忘记。举个例子,有人插入了一个条件return

go func() {
    defer wg.Done()
    for i := 0; i < n; i++ {
        ch <- i
        if i == 3 {
            return
        }
    }
}()

使用defer,这不会是一个问题,wg.Wait()仍然会被调用。如果没有defer,就不会有。
参见相关问题:
在循环中释放延迟资源的正确方法?
延迟调用的参数立即计算

相关问题