go

需求分析 (3个原因)

产生这个需求,通常有以下的原因:

  1. 这个 goroutine 的运行超出了太多预计的时间,以致后续的计算不再有意义
  2. 这个 goroutine 阻塞在某个 read/write channel 变得没有响应
  3. 这个 goroutine 阻塞在某个系统调用,外部调用或业务逻辑的死循环

这种时候很自然地就会产生“主动外部 kill goroutine”的需求 (正如手动结束掉一个无响应的进程那样)。

然而 goroutine 被设计为不可以从外部无条件地结束掉,只能通过 channel 来与它通信。也就是说,每一个 goroutine 都需要承担自己退出的责任。(A goroutine cannot be programmatically killed. It can only commit a cooperative suicide.)

以下我们分可响应 (1 & 2) 和不可响应 (3) 两种情况分开讨论

处理仍可响应 channel 的 goroutine (1 & 2)

最直接的方法是关闭与这个 goroutine 通信的 channel close(ch)。如果这个 goroutine 此时阻塞在 read 上,那么阻塞会失效,并在第二个返回值中返回 false (此时可以检测并退出);如果阻塞在 write 上,那么会 panic,这时合理的做法是在 goroutine 的顶层 recover 并退出。

更健壮的设计一般会把 data channel (用于传递业务逻辑的数据) 和 signal channel (用于管理 goroutine 的状态) 分开。不会让 goroutine 直接读写 data channel,而是通过 select-default 或 select-timeout 来避免完全阻塞,同时周期性地在 signal channel 检查是否有结束的请求。

以上的方法可以处理前两种情况。

处理无法响应 channel 的 goroutine (3)

对于第三种情况,程序员能做的就是:

  1. 尽量使用 Non-blocking IO (正如 go runtime 那样)
  2. 尽量使用阻塞粒度较小的 sys calls (对外部调用也一样)
  3. 业务逻辑总是考虑退出机制,编码时避免潜在的死循环
  4. 在合适的地方插入响应 channel 的代码,保持一定频率的 channel 响应能力

关于 blocking syscall,需要注意的是 Go runtime 会启动新的 OS 线程去调度剩下的 goroutines,如果不能及时从阻塞中恢复并持续有新的 blocking goroutine 的话,OS 线程数量会线性地增长,这是一种非常不理想的情况,极端例子可以看下面的 "why 1000 goroutine generats 1000 os threads?"。

References

Gu Lu
2016-02-02

Comments
Write a Comment
  • 轩脉刃 reply

    goroutine 被设计为不可以从外部无条件地结束掉,只能通过 channel 来与它通信。确实,即使是使用Context,它本质也只是靠子goroutine接收context.Done()信号来自己关闭,如果子goroutine是个阻塞的,那么这个gorotine也只能一直跑完才能退出,只是主goroutine没有感觉了。

Tags

随笔   游戏开发   Bitcoin   BSV   Programming   C/C++   优化   Unity   C++   知乎   中国文化   Unity3D   游戏设计   区块链   比特币   小聪游戏   引擎设计   软件开发   idtech   SatoPlay   系统架构   Production   Bitcoin SV   加密货币   项目管理   游戏评论   SPV   资源管理   效率   网络   Visual Studio   Blockchain   Lua   Blockchain Computing   GDC   VR   PerfAssist   EMC   资源流水线   方法论   模板编程   Oculus   渲染   道德经   BitcoinSV   Unity MemoryProfiler   字体   Productivity   图形   Ethereum   nanomsg   摘录   同步技术   cppcon   C++模板   DOOM3   Surface Pro 3   Engine Evaluation   CRT   Bitcoin Cash   cppcon14   跨语言可变参数列表   团队协作   货币   开放世界   权利   slua   遮挡剔除   完美转发   协作式调度   Money   类型推导   Memory Debugging   个人成长   小故事   产品   错误处理   MOD   BCH   读书笔记   经济学   信息过载   行业报告   Modern C++   ETH   网络编程   协程   Premake   万物理论   测试   中间件   Game Engine   Michael Abrash   区块链游戏   CI   命令行解析   Science   goroutine   ndk   自动化   Scripting   Debugging   数据上链   技术评估   Unity GC   C++11   学习方法   Dice   Telemetry   笔记   golang   Methodology   图形编程   多线程   工程改进   Unity Coroutine   新手引导   Deployment   Visual Assist   文化   BTC   量子计算   域名   虚拟现实   系统重构   暴雪   exp   历史   Unity Profiler  

知识共享许可协议
本作品由Gu Lu创作,采用知识共享Attribution-NonCommercial-NoDerivatives 4.0 国际许可协议进行许可。