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

shstlldc  于 2023-09-28  发布在  Go
关注(0)|答案(1)|浏览(182)
  1. go func() {
  2. defer wg.Done()
  3. for i := 0; i < n; i++ {
  4. ch <- i
  5. }
  6. }()
  1. go func() {
  2. for i := 0; i < n; i++ {
  3. ch <- i
  4. }
  5. wg.Done()
  6. }()

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

nhaq1z21

nhaq1z211#

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

  1. go func() {
  2. defer wg.Done()
  3. for i := 0; i < n; i++ {
  4. ch <- i
  5. if i == 3 {
  6. return
  7. }
  8. }
  9. }()

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

展开查看全部

相关问题