自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

淺析Lua下實現(xiàn)搶占式多線程

移動開發(fā) iOS
淺析Lua下實現(xiàn)搶占式多線程是本文要介紹的內(nèi)容,主要是來學(xué)習(xí)lua的多線程,關(guān)于線程的問題,我們來看本文詳解。

淺析Lua下實現(xiàn)搶占式多線程是本文要介紹的內(nèi)容,主要是來學(xué)習(xí)lua多線程。Lua 5.2 的開發(fā)進(jìn)度可以回溯到 2010 年 1 月。漫長的流程到今天已經(jīng)快兩年過去,終于等到了 beta 版。我十分期待它可以在 2011 年內(nèi)正式發(fā)布。在這幾經(jīng)折騰的兩年里,許多新特性企圖擠進(jìn) 5.2 版,又最終被否決。

當(dāng)我們審視改進(jìn)列表,似乎看不到太多耳目一新的東西。但如果仔細(xì)閱讀一下源代碼,就會發(fā)現(xiàn),大部分地方都重新實現(xiàn)過了,以配合這些表面上看起來不大的修改。如果你對 Lua 有足夠理解,會發(fā)現(xiàn),這次最激動人心的改進(jìn)是 "yieldable pcall and metamethods" 。官方也把之列為 Main changes 第一條。語言上的重大新特性 goto 卻被列在末尾。

當(dāng)然,這只是我粗淺的理解而已。沒有經(jīng)過實踐使用 5.2 一段時間,下這樣的論斷有點太草率。不過我還是想談?wù)?,這點改進(jìn)可以給我們的開發(fā)帶來什么。

coroutine 的 yield 現(xiàn)在幾乎可以在任何地方使用了。我用了幾乎,是因為它依然有一些限制。這些限制不大容易說的很清楚,為了理解其限制,我花了一整天實現(xiàn)閱讀 lua 5.2 beta 版的源代碼。這個話題下次有機(jī)會我再另寫一篇 blog 總結(jié)一下。今天只談應(yīng)用。

我們知道 coroutine 可以實現(xiàn)一個協(xié)同多線程模型。即,每個線程(coroutine) 只在用戶期望的地方跳出來,并可以在以后跳回去(保持當(dāng)初跳離的狀態(tài))。這解決了許多搶占式多線程的麻煩。lua 的發(fā)明人在一篇訪談中談到了 coroutine 解決并發(fā)的問題。

但是,讓用戶不厭其煩的寫 yield 是件很討厭的事情。往往框架會把 yield 調(diào)用藏起來。如果我沒記錯,我讀過的早期的 kepler 框架就是把 yield 藏在 html 的輸出里的。能夠想到的更漂亮的做法是編寫一個 lua debug hook ,在 hook 里調(diào)用 yield 。這樣就可以讓 lua vm 每跑幾行 lua byte code 就自動做 yield 一次。

可惜的是,lua 5.1 以前的版本不支持這個。因為 yield 限制太多了。如果恰巧 yield 發(fā)生在一次 metamethod 調(diào)用內(nèi)部,或 pcall 內(nèi)部,就會失敗。這和 C/Lua 函數(shù)嵌套有關(guān)。lua vm 在實現(xiàn) pcall 及 metamethod 機(jī)制時,不斷的在 C 函數(shù)以及 lua 函數(shù)間跳轉(zhuǎn)。

一旦 yield 發(fā)生在多層 C 函數(shù)與 lua 函數(shù)嵌套調(diào)用的內(nèi)部。用 longjmp 返回的 yield 機(jī)制,會丟失 C 函數(shù)調(diào)用的 stack frame 。也就是說,lua vm 本身的狀態(tài)可以保留在 L 中,但 C 函數(shù)的狀態(tài)卻丟失了,無法正確返回。Lua 5.2 為了解決這個問題,引入了新的 api ,有興趣可以閱讀新的文檔的 4.7 – Handling Yields in C 。不過真的想全部搞清楚,還是推薦閱讀一下源代碼。

只使用系統(tǒng)自帶的 debug 庫是不夠的。用 lua 的 debug.sethook 設(shè)置一個 lua 函數(shù)做 hook ,里面依然不能調(diào)用 coroutine.yield 。這還是受到了 lua 實現(xiàn)的限制。正確的方法是直接使用 C api lua_sethook,把這樣一個 hook 函數(shù)設(shè)進(jìn)去:

  1. static void  
  2.  
  3. hook(lua_State *L, lua_Debug *ar)  
  4. {  
  5.     lua_yield(L,0);  

至于你想讓它每隔幾行 lua 代碼 yield 一次,還是讓它發(fā)生在函數(shù)調(diào)用的時候,這看你的喜好。但一旦設(shè)置成功,一段 lua 代碼就可以透明的定期 yield 出來了。

這些有什么用?我設(shè)想了兩種用法,

一、是用 lua 做一個調(diào)度器,模擬出一個搶占式的多線程庫。本質(zhì)上,這個庫是基于 coroutine 實現(xiàn)的。但切換線程是利用的 debug hook 定期強(qiáng)制切換?;谶@個庫,可以把以前我寫過的這個小玩意改進(jìn)一下。做的更易用一些。

二、是在一個 os 進(jìn)程內(nèi)啟動多個獨立的 lua state ,每個 lua state 并不包含多個 coroutine ,而只用一個 main thread 。設(shè)置 debug hook ,讓 main thread 可以每跑一個階段就 yield 出來,把控制權(quán)交還到上層的 C 代碼。在 C 層次寫一個有效的調(diào)度器。對 lua state 來說,每個都是獨立的,它們之間可以通過 zeromq 這樣的庫通訊。lua state 還可以部署到多個 os thread 上,實現(xiàn)一個 M:N 的線程模型。它的調(diào)度器會比 os 來的更為高效。(關(guān)于在語言級實現(xiàn) M:N 線程模型和 OS 級實現(xiàn) M:N 線程序模型的性能差異,上個月 7 月 12 日我們在 google+ 上做過一次討論??上窃谟邢奕ψ永镒龅?,暫時沒找到方法公開)且少占用大量的堆棧資源。

話說到這里,再看看,其實這不就是 Erlang 的模型么?:)

ps. 其實 lua 的早期版本也可以通過 lua coco 實現(xiàn)無限制的 yield 操作。但 coco 使用了 OS 的 fiber 庫 這比 5.2 版的 lua 實現(xiàn)多出了額外的堆棧開銷。

一些還沒實現(xiàn)的想法:游戲服務(wù)器里的 npc ai 等東西是不是可以放在一個個獨立的 lua state 中完成?它們相互不影響,用消息交互??梢砸婚_始分配好一個 state 池,用來動態(tài)綁定新的 AI 單位(減少啟動初始化的代價)。把任務(wù)切分成獨立的小單位,在獨立的 lua state 中做,我想對 lua 的 gc 操作也是極為有利的。

小結(jié):淺析Lua下實現(xiàn)搶占式多線程的內(nèi)容介紹完了,希望通過本文的學(xué)習(xí)能對你有所幫助!

責(zé)任編輯:zhaolei 來源: 互聯(lián)網(wǎng)
相關(guān)推薦

2010-02-01 17:25:09

Python多線程

2009-08-12 18:04:44

編寫C#多線程

2010-03-03 17:44:07

Python多線程

2011-04-08 10:36:38

MFC多線程

2009-07-03 17:18:34

Servlet多線程

2009-07-17 17:29:13

多任務(wù)多線程

2011-08-31 16:22:51

LUA多線程

2011-08-31 16:30:19

Lua多線程

2011-06-24 11:12:39

Qt 多線程 線程

2011-06-24 11:03:31

Qt 多線程 線程

2009-04-27 13:15:04

多線程方法run()

2009-08-21 11:31:59

異步和多線程的區(qū)別

2011-04-13 14:53:32

2009-08-28 15:57:56

C#線程傳遞參數(shù)

2023-10-19 08:30:58

線程源碼thread

2011-10-31 15:59:56

SQLiteiPhoneiOS

2009-09-14 19:21:36

Javascript透

2020-03-31 08:05:23

分布式開發(fā)技術(shù)

2009-08-27 14:29:28

顯式實現(xiàn)接口

2014-08-13 10:41:08

linux線程
點贊
收藏

51CTO技術(shù)棧公眾號