【转】Lua coroutine 不同的多线程编程思路

Lua coroutine 不同的多线程编程思路

上周末开始看《Lua程序设计》第二版,目前体会到其中比较有趣的有两点,一是强大的table数据结构,另外就是coroutine。也许Lua 中的coroutine是一种很好的设计模式,但我初步的体会仍是没想到其余语言和场合能很是适合用到coroutine的场景。php

1、简介

协同程序与线程差很少,也就是一条执行序列,拥有本身独立的栈,局部变量和指令指针,同时又与其它协同程序共享全局变量和 其它大部分东西。线程与协同程序的主要区别在于,一个具备多线程的程序能够同时运行几个线程,而协同程序却须要彼此协做地运行。就是说,一个具备多个协同 程序的程序在任什么时候刻只能运行一个协同程序,而且正在运行的协同程序只会在其显示地挂起时,它的执行才会暂停。html

如:java

co = coroutine.create(function ()
for i=1,10 do
print("co", i)
coroutine.yield()
end
end)

从主线程调用
coroutine.resume(co)
会依次打印1到10python

2、原理探析

  • coroutine建立的所谓的“线程”都不是真正的操做系统的线程,其实是经过保存stack状态来模拟的。
  • 因为是假的线程,因此切换线程的开销极小,同时建立线程也是轻量级的,new_thread只是在内存新建了一个stack用于存放新coroutine的变量,也称做lua_State

LUA_API lua_State *lua_newthread (lua_State *L)编程

  • 调用yield()当前线程交出控制权,同时还能够经过stack返回参数。调用resume的线程(可理解为主线程)得到返回的参数。
  • Lua yield()和Java中的Thread.yield()有点类似,可是区别更大。Java中的yield调用后只是将当前CPU切换到另一个线程,CPU可能随时会继续回到线程执行。
  • 我更倾向于把Lua中的yield()和resume()和Java中的wait()和notify()来对比。它们表现的行为基本一致。
  • 关于stack实现也可参看Yufeng(Erlang高手)的分析文章 lua coroutine是如何实现的?

3、Why coroutine?

上面对coroutine有个基本的了解,所以你们都会象我同样去想,为何要用coroutine?先研究下优势设计模式

  • 每一个coroutine有本身私有的stack及局部变量。
  • 同一时间只有一个coroutine在执行,无需对全局变量加锁。
  • 顺序可控,彻底由程序控制执行的顺序。而一般的多线程一旦启动,它的运行时序是无法预测的,所以一般会给测试全部的状况带来困难。因此能用coroutine解决的场合应当优先使用coroutine。

再看缺点,研究coroutine缺点以前,我寻找了一下Lua中为何实现coroutine的一些说明。在巴西人写的paper Coroutines in Lua(pdf)中解释了几个缘由:数据结构

  • Lua是ANSI C实现的,ANSI C并不包含thread的实现,所以若是要在Lua增长thread的支持就要使用操做系统本地的实现,这样会形成通用的问题。同时也会使Lua变得臃肿。所以Lua选择了在ANSI C上实现的coroutine。
  • Lua主要设计目的之一是给C调用,若是Lua内部又有多线程实现的话会形成C调用状态的混乱,而只提供coroutine层面的挂起则能够保持状态的一致性。

以上这些理由都是基于Lua特殊的缘由而使用的,并非很通用的缘由。咱们也了解到,coroutine其实是一种古老的设计模式,它在60年代 就已经定型,可是现代语言不多有重视这个特性,目前能够举例的有Windows的fibers, Python的generators多线程

4、Lua coroutine和Erlang

上面优势有1条没展开,就是每一个coroutine有本身私有的stack及内存变量空间。所以能够认为coroutine和Erlang中的 process是很是类似的。可是coroutine只能同时只有一个在执行,若是能让他多个同时跑,我以为就和Erlang很是类似了。模块化

《Lua程序设计》第二版30.2介绍的一种实现方法,让多个c threads启动,而后每一个c thread启动一个coroutine(相似Erlang process),而后经过stack传递变量值(相似Erlang process message),这样就能够实现一个相似Erlang的process模型了。因为coroutine实际上能够用任何语言实现,那其余语言应该也可实 现一样这种设计方法。post

5、Lua其余

Lua目前主要用在游戏编程领域,一般的观点Lua是“胶水语言”。用来把各个模块化的功能粘合起来。就我目前阅读的一些代码来看,C和Lua一般 是混合在一块儿的,并无明确的边界。对于我一个外行的眼光看来我分不清哪些是在作C的事情,哪些是在调用Lua。特别是这个“胶水”若是放得太多,系统中 各个模块的独立性将会受到影响。好比云风的这篇Lua 不是 C++也提到,“这属于过厚的粘合层,是绝对须要抛弃的”。

另外Code@Pig一篇[网游设计] 一点感想也提到要简化调用,我总结它的观点主要两点:

  1. 不要存在冗余的关系,给一个部分负责管理就好。(由Lua/python来管理)
  2. 粘合层(Lua/python接口)不要过胖,咱们能够经过引入一个“间接层”来把粘合层作“薄”

虽然Lua的高效和精简的设计让人赞誉有加,可是它的性能排名并不高,和Python大体在同一个级别。另外“胶水语言”的定位也妨碍了它在更多领域的发展。