一段 Go 代码执行疑问,关于 defer 执行时机的问题

2023-06-30 11:22:28 +08:00
 CarrieBauch

问一个 Go 程序的执行问题

下面的代码中,我虽然知道了 1s 之后,会执行 case <-ctx.Done() 这个 case 。但是我想搞清楚原理:

我有一个疑问:

  1. defer cancel() 是需要等到 main 函数返回才可以执行
  2. 从程序代码中看,下面的程序中,执行 select 的时候,都会阻塞住才对
  3. 如果 select 都会阻塞住的话,那就没有办法执行 return 了,如果没有执行 return 的话,那就不应该执行 defer cancel() 才对
package main

import (
	"context"
	"fmt"
	"time"
)

const shortDuration = 1 * time.Second

func main() {
	timeNow := time.Now()
	ctx, cancel := context.WithTimeout(context.Background(), shortDuration)
	defer cancel()
	select {
	case <-time.After(2 * time.Second):
		fmt.Println("overslept")
	case <-ctx.Done():
		fmt.Println(ctx.Err())
	}
	fmt.Println(time.Since(timeNow))

}

1334 次点击
所在节点    Go 编程语言
6 条回复
9313841411
2023-06-30 11:31:51 +08:00
1s 后
case <-ctx.Done():
fmt.Println(ctx.Err())
会被执行 select 执行完成 -> main 函数退出
zeonluang
2023-06-30 11:34:15 +08:00
select 在 case <-ctx.Done():这行就满足条件了吧,然后 return 了。
return 之后再调用了 cancel()
mcfog
2023-06-30 11:35:41 +08:00
想说看文档结果发现这段程序就是文档,那你继续看一下 WithTimeout 和关联的 WithDeadline 的文档里的描述,这里并没有什么原理,就只是文档描述的行为

另外看你的描述,如果你认为代码的执行顺序是 1 秒后执行了 cancel(),然后 select 进第二个 case ,我建议你把 defer cancel()这部分改成
defer func(){
LOGSOMETHING;
cancel()
}()
确认一下执行顺序,再看一下文档理解一下
Trim21
2023-06-30 11:38:09 +08:00
这里的 context.WithTimeout 会启动一个 goroutine ,在 1s 之后 canal 掉这个 ctx

这里的 select 无论如何都不会阻塞,无论是 1s 之后的 ctx.Done() 还是 2s 之后这个 timer 会返回,都会让这个 select 继续运行...
CarrieBauch
2023-06-30 11:58:25 +08:00
@mcfog
谢谢你,程序改为下面的这样的,就清晰很多了。

结论就是你说的,不是 defer cancel() 让 -ctx.Done()。而是时间到了之后,ctx.Done 里面就会有消息写入了。

defer cancel() 其实就是一个兜底的策略,可以取保 main 返回的时候,可以 cancel 掉

```
package main

import (
"context"
"fmt"
"time"
)

const shortDuration = 1 * time.Second

func main() {
timeNow := time.Now()
ctx, cancel := context.WithTimeout(context.Background(), shortDuration)
//defer cancel()
defer func() {
time.Sleep(5 * time.Second)
fmt.Println(1111)
cancel()
}()
select {
case <-time.After(2 * time.Second):
fmt.Println("overslept")
case <-ctx.Done():
fmt.Println(ctx.Err())
}
fmt.Println(time.Since(timeNow))

}

```
CarrieBauch
2023-06-30 12:01:14 +08:00
咦,玩 V 站不久,回复里面竟然无法使用 markdown 格式

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/952954

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX