英文:
can I omit defer keyword in this case?
问题
这两段代码是相同的吗?运行它们看起来是一样的,我见过两种写法。
英文:
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()
}()
Are these two code the same? Seems the same running them and I have seen both writings.
答案1
得分: 2
这两个看起来是相同的,但也可能存在它们不同的情况。这是因为如果函数发生恐慌,延迟函数也会被执行。
例如,如果ch
是一个关闭的通道,在关闭的通道上发送数据会导致恐慌(参见https://stackoverflow.com/questions/39015602/how-does-a-non-initialized-channel-behave/39016004#39016004),如果没有使用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
,它将不会被调用。
参考相关问题:
英文:
Those 2 seem to be identical, there may be cases when they're not. That's because deferred functions are also executed if the function is panicking.
So for example if ch
is a closed channel, sending on a closed channel will panic (see https://stackoverflow.com/questions/39015602/how-does-a-non-initialized-channel-behave/39016004#39016004), and without defer
wg.Done()
will not be called. With defer
, it will be. This may be very important for another goroutine calling wg.Wait()
to get unblocked.
Another difference is that the deferred function and its arguments are evaluated when the defer
statement is executed, in your case before the loop. If the wg
variable would be modified e.g. after the first send, the one with defer
would not see the new value of wg
, the one without defer
would see that as it's evaluated after the loop.
All in all, use defer
when it makes sense, and even if you or someone else later end up modifying / extending the code, it will not be forgotten. Just think of an example where someone inserts a conditional return
:
go func() {
defer wg.Done()
for i := 0; i < n; i++ {
ch <- i
if i == 3 {
return
}
}
}()
Using defer
, this won't be a problem, wg.Wait()
will still be called. Without defer
, it won't be.
See related questions:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论