@
RudyC #20
是多协程工作的时候,多个协程的 IO 操作让 golang 给接管了,golang 应该有一个机制 将 IO 调用单独用一个线程来处理 派发 响应,像 epoll 调用就可以使用水平触发来 监听多个 fd,这样语言层面上,只要一个线程就能接管跟系统调用的操作,这样其它 golang 的线程就不用频繁进入内核态了,进入内核态首先要切换 MMU 的页表,L1 L2 cache 可能还会被 invalid 掉,单次内核态切换开销小,但是如果上千个线程的内核态频繁切换开销就大了,切换少了,很容易把线程给饿死,不频繁切换是不可能的。但是像 Java 这种线程池模型,你只能拿线程池死扛,没有其它好办法,因为语言层面上就没做协程,后续的版本可能会推出。
另外协程也有自己的问题,就是公平调度的问题,万一一个协程长期跑着,不退让 CPU,这样可能其它协程就饿死了,在调度算法上面还需要做很多处理,至于协程的中断,可以参考 Java 的 GC safePoint 实现,应该是使用 Linux 的 mprotect 系统调用,在特定的汇编地址下,插入一些 nop 代码,当操作系统检测到 CPU 运行到这个地址的时候,就会触发软中断跳转到 mprotect 事先设置的回调调用
有兴趣的朋友最好了解一下 epoll 跟 mprotect 调用,这两个函数读完说明书,基本上就了解协程是如何实现的了