coroutine
线程是操作系统级别的概念,现代操作系统都实现并且支持线程,线程的调度对应用开发者是透明的,开发者无法预期某线程在何时被调度执行。基于此,一般那种随机出现的BUG,多与线程调度相关。
coroutine则是一个概念,windows上有所谓的fiber纤程实现,而好些语言中也自带coroutine的实现,比如Lua。与线程最大的不同是,coroutine的调度/挂起/执行开发者是可以控制的。另外coroutine也比线程轻量的多。要在语言层面实现coroutine,需要内部有一个类似栈的数据结构,当该coroutine被挂起时要保存该coroutine的数据现场以便恢复执行。 ------------------------------------------------------------------------------------------
原理探析
- coroutine创建的所谓的“线程”都不是真正的操作系统的线程,实际上是通过保存stack状态来模拟的。
- 由于是假的线程,所以切换线程的开销极小,同时创建线程也是轻量级的,new_thread只是在内存新建了一个stack用于存放新coroutine的变量,也称作lua_State
- 调用yield()当前线程交出控制权,同时还可以通过stack返回参数。调用resume的线程(可理解为主线程)获得返回的参数。
- Lua yield()和Java中的Thread.yield()有点相似,但是区别更大。Java中的yield调用后只是将当前CPU切换到另外一个线程,CPU可能随时会继续回到线程执行。
- 我更倾向于把Lua中的yield()和resume()和Java中的wait()和notify()来对比。它们表现的行为基本一致。
Why coroutine?
上面对coroutine有个基本的了解,因此大家都会象我一样去想,为什么要用coroutine?先研究下优点
- 每个coroutine有自己私有的stack及局部变量。
- 同一时间只有一个coroutine在执行,无需对全局变量加锁。
- 顺序可控,完全由程序控制执行的顺序。而通常的多线程一旦启动,它的运行时序是没法预测的,因此通常会给测试所有的情况带来困难。所以能用coroutine解决的场合应当优先使用coroutine。