原文链接:https://medium.com/@matryer/golang-advent-calendar-day-two-starting-and-stopping-things-with-a-signal-channel-f5048161018

使用channel在goroutines中传递信号

在go里,使用channelgoroutines间交流数据是一个很好的方式,但是也可以使用它去传递信号。

传递信号时,使用空的struct作为channel的类型,只表示信息传递。更有趣的是,它不会占用内存空间,一个空的struct没有任何的属性。你可以到这里查看

这是一个信号channel

1
var signal chan struct{}

可以使用go的内置make函数初始化它:

1
signal := make(chan struct{})

代码会被阻塞,直到某些值被发送到channel中:

1
<-signal

在这个例子下,我们不在意它的值,这也是为什么我们不传递任何值给它。

类似的,在一个select语句,当收到goroutine外的信号时,可以使用一个关闭的channel去运行不同的代码。

等待某些操作的结束

通过一个阻塞的信号channel,可以等待另一个goroutine中的任务结束:

1
2
3
4
5
6
7
8
9
done := make(chan struct{})
go func() {
  doLongRunningThing()
  close(done)
}()
// do some other bits
// wait for that long running thing to finish
<-done
// do more things

同一时间执行多个任务

假设有很多的goroutine在排队,可以通过关闭一个信号channel去触发它们在同一个时间开始执行:

1
2
3
4
5
6
7
8
9
10
start := make(chan struct{})
for i := 0; i < 10000; i++ {
  go func() {
    <-start // wait for the start channel to be closed
    doWork(i) // do something
 }()
}
// at this point, all goroutines are ready to go - we just need to
// tell them to start by closing the start channel
close(start)

暂停任务

类似的,也可以使用它去暂停goroutines。当下面的goroutine从一个email channel中收到了数据会进行发送邮件的操作:

1
2
3
4
5
6
7
8
9
loop:
for {
  select {
  case m := <-email:
    sendEmail(m)
  case <-stop: // triggered when the stop channel is closed
    break loop // exit
  }
}

如果stop channel被关闭了,for循环就会退出,就不会有更多的邮件被发送。

  • 更多的channel可以做的事件,到这里查看:VIDEO: GopherCon 2014 A Channel Compendium by John Graham-Cumming.