chan bool如何让Goroutine等待?fsnotify场景疑问解析
理解fsnotify示例中done通道如何让主Goroutine保持等待
咱们先从Go程序的核心运行规则说起:只要主Goroutine执行完毕,整个程序就会立刻退出,不管其他后台Goroutine有没有执行完成。这就是为什么你移除done相关代码后,主Goroutine跑完watcher.Add就直接退出,后台监听文件事件的Goroutine也跟着终止了。
为什么done通道能让主Goroutine保持等待?
示例里的代码逻辑可以拆成这几步:
- 创建一个无缓冲通道
done := make(chan bool) - 启动一个匿名后台Goroutine,里面是无限循环的
select,一直监听watcher的事件和错误 - 主Goroutine最后执行
<-done——这是一个阻塞操作:主Goroutine会停在这里,直到有值被发送到done通道,或者通道被关闭
而示例里的匿名Goroutine根本没有往done通道发送值,也没有关闭它,这意味着<-done会永远阻塞主Goroutine,让它一直处于等待状态,不会退出,这样后台的文件监听Goroutine就能持续运行处理事件。
这种方式和sync.WaitGroup的区别
你提到sync.WaitGroup更符合Go语言习惯,这点没错:
WaitGroup的Add、Done、Wait语义非常明确,能清晰管理多个Goroutine的生命周期,比如你可以准确知道哪些Goroutine完成了,再让主Goroutine退出- 而示例里的
done通道其实是一种“极简的阻塞技巧”——它没有实际的信号传递意义,只是靠永久阻塞让主Goroutine不退出,属于快速实现的方式
如何让程序正常退出(扩展)
如果想要让程序能主动退出(比如收到终止信号),可以改造done通道的用法:
done := make(chan bool) // 监听系统信号 go func() { sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) <-sigChan close(done) // 收到信号后关闭done通道,解除主Goroutine的阻塞 }() // 原来的文件监听Goroutine... <-done // 主Goroutine在这里等待,直到done通道被关闭
当你按下Ctrl+C发送SIGINT信号时,done通道被关闭,<-done会解除阻塞,主Goroutine执行defer watcher.Close(),关闭watcher的Events和Errors通道,后台Goroutine的select会收到ok=false,进而退出循环,整个程序优雅终止。
内容的提问来源于stack exchange,提问作者mununki
相关产品推荐
相关产品推荐

