【发布时间】:2019-04-15 16:02:06
【问题描述】:
我有多个 goroutines select 来自两个通道:一个通道提供数据,一个通道用于信号(一种完成/退出通道)。
我使用信号通道来捕获信号(杀死)并优雅地关闭 goroutine。
我从package a 运行'worker' goroutines,而捕获信号的goroutine 函数从package b 运行。
我使用来自https://gist.github.com/reiki4040/be3705f307d3cd136e85 的信号包。
package a
import "sync"
WorkChan := make(chan int)
QuitChan := make(chan struct{})
func Stop() {
fmt.Println("Stop called, closing channel")
close(QuitChan)
}
func Work(wg *sync.WaitGroup) {
var item int
for {
select {
case item = <- WorkChan:
... processing
case <- QuitChan:
wg.Done()
return
}
}
}
捕获信号并调用a.Stop()的goroutine
package b
import (
"os/signal"
"os"
"syscal"
"a"
)
func Signal() {
sChan := make(chan os.Signal, 1)
signal.Notify(signalChan, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-sChan
switch s {
case os.Interrupt, syscall.SIGTERM:
a.Stop()
}
}
}
这是我的主要功能
package main
import (
"a"
"b"
"sync"
)
func main() {
var wg sync.WaitGroup
go b.Signal()
wg.Add(1) // for simplicity; actual code start multiple goroutines of Work
go a.Work(&wg)
// wait until work is done
wg.Wait()
fmt.Println("Done.")
}
当我终止正在运行的进程时,我看到来自Quit 的打印消息。我预计一旦通道关闭,goroutines 将在某个时候 select QuitChan 案例并返回。
但他们一直在奔跑;他们继续处理来自WorkChan 的项目。似乎它被忽略了。我在这里想念什么?
通道不会关闭吗?怎么还开着?
【问题讨论】:
-
当你关闭
a.QuitChan,这将终止a的goroutine(迟早),但是b包中的goroutine没有终止条件,它将永远运行。此外,应用程序不会因为某些“随机” goroutine 结束而终止,应用程序会在maingoroutine 结束时终止(我们不知道您的maingoroutine 是什么)。 -
您能详细说明“他们一直在运行”是什么意思吗?
-
b的 goroutine 中有一个循环,里面没有 return 和 break 语句,所以它会一直运行。 goroutine 或其循环不会因为独立的 goroutine 结束而神奇地结束或返回。 -
仅仅因为您看到
"Stop called, closing channel"打印,这并不能保证QuitChan已关闭(因为打印在close()调用之前)。在close()之后添加打印语句并确认您是否看到打印。 -
您正在复制 WaitGroup。请改用指针。我认为
go vet应该抱怨这一点。