关于Golang信号channel的长度问题

钱文品 · · 4060 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

首先来看一下一个简单的信号处理的例子

package main

import (
	"fmt"
	"os"
	"os/signal"
)

func main() {
	c := make(chan os.Signal, 1)   # watch this
	signal.Notify(c, os.Interrupt)

	s := <-c
	fmt.Println("Got signal:", s)
}

首先创建一个容纳信号对象的channel,channel的长度为1。

然后使用Notify注册信号处理,将Interrupt信号和channel关联起来。

进程挂在那里休眠,直到收到一个ctrl+c触发了Interrupt信号,channel里就会被塞进一条信号对象,<-c就会返回,打印信号对象然后退出程序。

上面这个例子是官方文档里提供的一个信号处理的简单例子。

值得注意的是这里的channel是非阻塞型channel,长度为1。那能不能是非阻塞型channel呢,能不能是长度为N的阻塞型channel呢?

我们先看看官方的文档里怎么说的

文档里的relay这个单词很有意思,它的英文是传达、转播,有点像代收的意思。

Notify会使得参数c[channel]来代收输入信号。如果信号参数sig未提供,就会代收所有类型的信号。否则只代收参数里提供的信号类型。

信号代收是非阻塞的,什么意思呢?

如果channel满了,被代收的信号就会被抛弃,因为没有空间容纳了。代收的过程等价于

select {
    case c<-sig:
    default:
}

如果channel的长度为1,当一连串的信号同时到达,只会有第一个信号会被代收,如果channel消费者没有来得及处理的话。

如果channel的长度为0,信号可能会丢失。比如下面的代码

package main

import (
	"fmt"
	"os"
	"os/signal"
        "time"
)

func main() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)

	time.Sleep(5 * time.Second)

	s := <-c
	fmt.Println("Got signal:", s)
}

我们在程序Sleep的时候狂按ctrl+c持续2秒,然后等待到5秒的Sleep结束,你会发现程序依然挂在那里,不会退出,这时需要再按一下ctrl+c才会退出。

阅读更多相关文章,关注知乎专栏【码洞】


有疑问加站长微信联系(非本文作者)

本文来自:知乎专栏

感谢作者:钱文品

查看原文:关于Golang信号channel的长度问题

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

4060 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传