掌握 Go 并发:玩转 Channel
我曾经用 Go 构建过一个图像处理流水线。
我在每一步都使用了 goroutine。我用 channel 将它们连接起来。我点击了运行。
程序卡死了。内存占用不断攀升。然后它崩溃了。没有任何错误提示。只有一片死寂。
我浪费了几个小时去调试一个损坏的调度器。但我错了。我并不理解 channel 的工作原理。
以下是防止 Go 程序挂起的三个规则。
- Nil channel 是黑洞 Nil channel 会永久阻塞。如果你在 nil channel 上发送或接收,goroutine 会一直卡在那里。
- 始终使用
make初始化你的 channel。 - 如果不确定,请进行 nil 检查。
- 关闭规则可防止 panic 关闭一个 channel 是永久性的。
- 只有发送方应该关闭 channel。
- 向已关闭的 channel 发送数据会导致 panic。
- 使用第二个返回值来检查 channel 是否已关闭:
v, ok := <-ch。 - 如果
ok为false,则表示 channel 已关闭。
- 使用 channel 方向确保安全 Go 允许你指定 channel 是用于发送还是接收。
chan<- int表示你只能发送数据。<-chan int表示你只能接收数据。- 这会强制编译器在运行代码之前捕获错误。
如何构建一个清晰的流水线:
- 使用
defer close来确保 channel 仅被关闭一次。 - 使用
range来遍历 channel。当 channel 关闭时,它会自动停止。 - 为你的函数指定方向类型,以建立严格的契约。
当你遵循这些模式时,可以防止泄漏和 panic。你构建的系统将易于测试且稳健。
你的挑战:
编写一个函数,将多个输入 channel 合并为一个输出 channel。使用 select 循环。添加 500ms 的超时机制。确保没有 goroutine 泄漏。
在评论区提交你的解决方案。