神秘使者“久闻Java语言跨越平台框架众多不过二十年功夫就已晋升天下第一编程语言今日一见果然名不虚传呐”“使者先生您过奖了咱们快些走国王陛下已经等候多时了”今日Java帝国朝堂之上迎来了一位神秘的来宾。来到大殿之上只见国王正襟危坐闭目养神不怒自威堂下群臣咸集纷纷侧目。“来者何人”国王一旁的内侍问到。“我乃GoLang帝国使者——Goroutine”使者答道。“GoLang帝国何方番邦小国寡人竟从未听闻”国王闭眼说到。说罢群臣皆笑了起来。“来此所为何事”内侍继续问到。使者回答“我此行特为传道而来”说完国王睁开了眼睛“传道我Java帝国乃天下第一编程帝国只有我们传出去哪有学别人之道”使者不卑不亢说到“Java帝国虽如日中天但却有一处缺陷假以时日必成大患”“哦你倒是说说看如若言语不通即刻轰出殿去。”国王厉声喝到。“敢问陛下Java线程执行到阻塞函数时该当如何”使者问到。一旁的线程大臣见状上前说到“遇到阻塞那自然要被操作系统挂起切换到别的线程”“敢问大人线程切换是否需要成本如果大量线程频繁切换成本又当如何”使者追问到。“你若关心这个问题那就不用阻塞函数通过异步回调来进行”线程大臣答道。使者嘴角上扬微微一笑“好一个异步回调异步回调确实不用阻塞不过它有两宗罪其一割裂了原来的代码业务逻辑其二陷入回调地狱难以维护”“这也不行那也不行你这人还真难伺候”线程大臣有些急了。使者转身面向国王说到“启禀陛下我有一法可让线程遇到阻塞函数后不需切换线程也不用异步回调还可以继续运行下去是高并发开发神技”国王一听来了兴趣“哦还有这种事说来听听”使者拜了一拜说到“线程可以在遇到阻塞的地方后保存执行的上下文转而去执行别处的代码。待阻塞的请求完成后再转而回去继续执行”国王不解问到“什么叫转而去执行别处的代码什么叫回去继续执行这函数执行到一半还能中途退出再回来”“是的没错”使者回答。此话一出朝堂上议论纷纷群臣都露出了鄙夷的笑容。“简直荒谬函数执行从进入到return退出从来都是一气呵成哪有中途执行一半退出再回来接着执行的道理简直闻所未闻”一旁的线程大臣说到。使者继续说到“一气呵成恐怕不是吧线程执行函数中途遇到时间片用完或者遇到I/O阻塞就会被操作系统保存上下文后挂起切换到其他线程。而后等到机会再回过头继续执行不是吗”线程大臣怒斥道“强词夺理你说的这情况是操作系统在调度管理多个线程对咱们的应用层线程来说都是透明的无需关心”使者没有退让却问道“既然操作系统可以调度管理多个线程那为何线程不可以调度管理函数的执行”群臣再次交头接耳议论起来。“陛下此番邦使者妖言惑众微臣建议即刻逐出大殿以正视听”国王应允随即遣人上前。不待侍卫上前使者自行离去边走边说到“可叹堂堂Java帝国却容不下一个新技术”临别相会使者心灰意冷打算离开Java帝国却在半道上被人给拦了下来。“先生请留步我家主人请先生府上相会”使者来到府上原来主人乃当地一富豪乡绅。“先生今日在朝堂之事我已听说在下对先生提到的函数执行过程中可中断和恢复的技术颇有兴趣还请先生不吝赐教”主人说完拜了一拜。“赐教不敢当我此次来Java帝国所传之道名叫协程是一种高并发开发的绝技可无奈贵国国君与大臣皆不识货无功而返可惜啊可惜”使者叹息到。“协程这是何物我只听说过进程和线程却是从未听过协程”使者起身说到“线程是操作系统抽象出来的执行流由操作系统统一调度管理。那在一个线程中同样可以抽象出多个执行流由线程来统一调度管理。这线程之上抽象的执行流就是协程”主人有些不解问到“一个线程怎么会有多个执行流呢”“这便是我今日在朝堂上说的线程执行函数遇到阻塞后可以保存上下文后退出转而执行别处的代码这里就从一个执行流转向了另外的执行流”使者解释到。主人拍案而起“原来是这个意思妙哉妙哉啊不过这线程是操作系统在调度管理那线程里抽象出来的执行流也就是协程该怎么调度管理呢操作系统可以通过时钟中断和系统调用进入内核来剥夺线程的执行权那线程该如何剥夺协程的执行权来实现调度管理呢”“真是个好问题线程的调度由操作系统来管理是抢占式调度。而协程不同协程需要互相配合主动交出执行权这也是协程的名字——协作式程序的来历”“主动交出执行权如何办到”主人追问。“办法有很多比如C帝国有一协程框架名叫libco他通过HOOK关键的系统函数来实现调度器的介入”“那你们Golang是怎么做的也是这样吗”“我们Golang帝国可不一样我们先天设计就是支持协程系统调用都被我们封装好了应用程序调用时遇到需要阻塞的像是文件读写Read/Write、Sleep我们的调度器就能有机会介入去执行调度管理了”使者得意的说到。