非阻塞式執行 Lua

lua-users home
wiki

使用 Lua 的 C 程式必須透過呼叫 API 函式來執行 Lua 程式碼,而 Lua 程式碼將執行直到停止或中斷。API 函式會封鎖 C 程式的執行,直到程式碼載入完畢。這項建議可讓 C 程式執行 Lua 程式碼而不會遭到封鎖。

目前,Lua 程式碼的執行方式如下

1. 載入 Lua 指令碼
2. 執行 Lua 指令碼
(Lua 指令碼將執行直到載入完畢。C 程式遭到封鎖。)
3. 結束
如果 Lua 指令碼出現問題,C 程式能執行的動作非常有限。Lua 指令碼可能會進入無限迴圈,進而使 C 程式陷入僵局。

應該提供 API 功能,讓 C 程式一次執行部分 Lua 程式碼。例如,可以提供一個函式來執行下一個 Lua 動作,然後將控制權傳回 C 呼叫方。Lua 程式碼的執行方式如下

1. 載入 Lua 指令碼
2. 執行下一個 Lua 動作
3. 執行只有 C 程式才能執行的其他動作
4. 如果指令碼載入完畢,結束
5. 否則,執行步驟 2

C 程式不會遭到 Lua 封鎖,而且它可以進一步控制 Lua VM。只要指令碼本身可以處理,在兩個動作之間讀取和修改 Lua 狀態(變數等)應該都是安全的。C 程式也應該隨時可以停止 Lua 指令碼。


目前的解決方案包括設定一個除錯掛勾,而這個掛勾會每 100 個動作呼叫一次,然後在除錯掛勾中呼叫 lua_yield。這樣一來,控制權將傳回啟動 Lua 的 C 程式碼,而且 C 可以使用 lua_resume 重新輸入 Lua 指令碼。這個解決方案在聊天記錄 ([1]) 和論壇 ([2]) 中都有所探討。不幸的是,如聊天串中所討論的,如果 Lua 指令碼本身使用協同程式,這個解決方案可能會失效。

在 Lua 5.1.1 中,一個稱為 luaV_execute 的內部函式會執行指令碼動作。它會在無限迴圈中執行動作。在動作之間,它會呼叫除錯掛勾。看來會有兩個基本原因導致此函式傳回:特殊指令碼動作和設定「中斷」狀態的除錯掛勾。(我不是 Lua 原始碼的專家,所以我的說法可能不正確)。也許最好的方法是擺脫無限迴圈,並進行一些 API 變更,允許 C 程式碼設定迴圈可能執行的次數。理想情況下,無需使用任何掛勾或呼叫回。


以下是不同的想法:讓 C 使用 Lua 註冊一個特殊掛勾,而這個掛勾會在動作之間呼叫,就像除錯掛勾一樣。但,這個掛勾有所不同
- 它不能由 Lua 指令碼變更,也不能指向 Lua 函式
- 鉤子的目的是告知 luaV_execute(透過回傳代碼)是否應該讓出或是不,以便呼叫 Lua 的 lua_pcall 或其他函數會回傳。
- 當 luaV_execute 「讓出」時,讓出的方式不同於 сопро程讓出,也就是說,使用這個鉤子讓出時,完全不會干擾 сопро程使用。

我想表達的是,我們應該能夠使用上面所述的「偵錯鉤子」方法,但是避免實際偵錯鉤子的缺點。C 編程人員可以完全控制 Lua 停止封鎖的時間。例如:每 100 個運算;每個運算;從不;… 等等。

這個做法可能涉及一些修改 Lua API 的地方。C 程式必須能夠從「讓出」處重新執行 Lua,但是也許不要使用以 сопро程為中心的 lua_resume 函數。讓 сопро程參與其中看起來是個壞主意,因為這樣 Lua 腳本可能就無法使用 сопро程。


我發現如果這個功能建議從未受到重視,我也可以使用自己的解決方案:Windows 光纖。這是目前我發現的執行該工作的最乾淨、最安全的方法,但是只能在 Windows 上執行。此外,您必須對 Lua 原始碼進行 Windows 專用的變更。由於範例大小的關係,因此放在另一個頁面中:NonBlockingLuaExecutionWithWindowsFibers


另一位 Lua 使用者需要非封鎖式 Lua 執行:[3]。我覺得我應該發起請願。;)


我認為 [debug.sethook] 可以用於此目的(參閱 PIL https://lua.dev.org.tw/pil/23.2.html)。這樣的按行中斷會對實作 Lua 偵錯器等事項很有幫助。--DavidManura

我不認為偵錯鉤子是好解決方案。我在聊天記錄檔中搜尋,一開始讀到的訊息是 [4]。Sittig 先生擔心 Lua 是否能從鉤子中乾淨地終止,以及如果腳本自行變更偵錯鉤子會發生什麼事。主要的問題是偵錯鉤子是在 Lua 中呼叫的;C 程式應該要驅動 Lua,而不是相反。

我和 RiciLake 討論了 luaV_execute 中的 while 迴圈。移除那個 while 迴圈,然後從程式碼反覆呼叫 luaV_execute 是一個顯而易見的做法,但問題點是 luaV_execute 是可重新進入(遞迴)的,因此您也需要移除那個遞迴(可能是堆疊做法?)以防止遞迴呼叫封鎖太久。--DavidManura

RecentChanges · preferences
編輯 · 瀏覽記錄
最終編輯:2006 年 9 月 10 日 上午 9:12 GMT (差異)