技术文摘
Golang 中带 default 分支的 select 语句无法接收 os.Signal 的原因
Golang 中带 default 分支的 select 语句无法接收 os.Signal 的原因
在 Go 语言开发过程中,不少开发者会遇到一个困惑:使用带 default 分支的 select 语句时,似乎无法正常接收 os.Signal 信号。要理解这一现象背后的原因,需要深入探究 Go 语言中 select 语句以及信号处理机制的工作原理。
来了解一下 Go 语言中的 select 语句。select 语句用于监听多个通信操作(如 channel 的发送和接收),当其中某个操作可以执行时,就会执行对应的 case 分支。如果有多个操作都可以执行,那么会随机选择一个执行。而 default 分支则在没有任何 case 分支可以执行时立即执行。
os.Signal 是 Go 语言用于处理系统信号的包。通过调用 signal.Notify 函数,我们可以将一个或多个信号与一个 channel 关联起来,这样当这些信号发生时,相应的信号值就会被发送到这个 channel 中。
当我们在 select 语句中使用带 default 分支来尝试接收 os.Signal 时,问题就出现了。这是因为 default 分支的特性导致的。由于 default 分支在没有其他可执行的 case 分支时会立即执行,这就使得 select 语句不会阻塞等待信号的到来。当信号还未发送到关联的 channel 时,default 分支已经被执行,从而导致信号无法被正确接收处理。
举个例子,如果我们编写如下代码:
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
)
func main() {
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
for {
select {
case sig := <-sigs:
fmt.Println(sig)
default:
fmt.Println("No signal received yet")
}
}
}
在这个代码中,default 分支会不断打印 “No signal received yet”,因为它不会等待信号到来,而是不断执行。
正确的做法是去掉 default 分支,让 select 语句阻塞等待信号,如下:
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
)
func main() {
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
sig := <-sigs
fmt.Println(sig)
}
这样,程序就可以正确接收并处理信号了。
在处理 os.Signal 时,使用带 default 分支的 select 语句会导致信号无法正常接收,我们应避免这种情况,确保信号处理逻辑的正确性。
- 十三项关键技能让开发者在人才市场备受青睐
- 彭哲夫在 WOT2016 中对运维人员的期许:来自科班出身开发者
- 15个给未来程序员的顶级职业建议
- 面向对象设计探讨:有状态类与无状态类的抉择困境
- 3年工作经验程序员面试感悟:应具备的技能
- GCC6热点技术:即将带来的新特性
- 集群调度框架架构的演进历程
- 传统程序员面临淘汰危机
- 项目为何耗时如此之久
- Badoo 因切换到 PHP7 节省 100 万美元
- 5个易被忽略的实用命令行工具
- 架构师养成的 7 个关键:思考、习惯与经验
- 金三银四跳槽季,开发者惊艳面试官之法
- 阚雷:从《中国制造2025》看制造业文艺复兴 | V课堂第13期
- 伪装成年薪20万刀以上码农的方法