【轉】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大體在同一個級別。另外「膠水語言」的定位也妨礙了它在更多領域的發展。

相關文章
相關標籤/搜索