根据
Ross Light的回答
所述:
如果您有多个资源,那么多个延迟通常是合适的。
2019年4月:但在这种情况下,请考虑Go 1.13(2019年第四季度),因为它集成了对
go问题14939:“运行时:defer很慢”和
go问题6980:“cmd/compile:在堆栈帧中分配一些延迟”的修复。
请参阅
Go CL 171758:“cmd/compile,runtime:在堆栈上分配延迟记录”。
When a defer is executed at most once in a function body,
we can allocate the defer record for it on the stack instead
of on the heap.
This should make defers like this (which are very common) faster.
This optimization applies to 363 out of the 370 static defer sites
in the cmd/go binary.
name old time/op new time/op delta
Defer-4 52.2ns ± 5
2019年10月(Go 1.13几周前发布)
这个
已经得到确认(Brad Fitzpatrick),与
CL 190098相符:
Cost of defer statement [ go test -run NONE -bench BenchmarkDefer$ runtime
]
With normal (stack-allocated) defers only: 35.4 ns/op
With open-coded defers: 5.6 ns/op
Cost of function call alone (remove defer keyword): 4.4 ns/op
但是
达米安·格里斯基补充道:
Defer gets cheaper, but panic/recover is more expensive.
Cost of defer: 34ns -> 6ns.
Cost of panic/recover: 62ns -> 255ns
这不是一个坏的交换。
换句话说,虽然使用多个defer可以成为惯用法,但这种做法由于性能成本而受到限制。然而,在Go 1.13+中,性能成本已不再是问题。(正如
Paschalis的博文"
defer是什么?你可以同时运行多少个?"所示)
这使得在代码流无关的位置执行函数调用成为
defer实际应用的可能。
然而,
John Refior指出
defer
是同步的:
实际上,defer会在函数退出之前立即执行。
它是同步的,所以调用者会等待defer完成。
因此,即使现在可以使用多个defer,请确保它们执行速度快,或者正如John所指出的那样:
Fortunately it’s easy to wrap a goroutine in a defer
, giving us the flow control and timing we want, without delaying the caller:
func Handler(w http.ResponseWriter, r *http.Request) {
log.Println("Entered Handler")
defer func() {
go func() {
time.Sleep(5 * time.Second)
log.Println("Exiting goroutine")
}()
log.Println("Exiting defer")
}()
}
Often defers are used for locking a mutex, or closing a connection or file descriptor, and the work they do is fast, or we want it to complete before the caller moves on.
But when you’re doing slow work that the client shouldn’t need to wait for at the end of an HTTP handler, making the call asynchronous can substantially improve user experience.
defer
会带来性能损耗。它非常微小(根据我在 go1.5.1 linux/amd64 上的测试大约为 75 纳秒),可能不值得考虑,但仍应该指出。 - HectorJ