非阻塞 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 的内部函数运行脚本操作。它在无限循环中运行操作。在操作之间,它会调用调试钩子。似乎有两个基本原因会导致该函数返回:特殊脚本操作和设置“yield”状态的调试钩子。(我不是 Lua 源代码专家,所以我可能错了)。也许最好是摆脱无限循环,并进行一些 API 更改,允许 C 代码设置循环可以运行的次数。理想情况下,不需要使用任何钩子或回调。


这里有一个不同的想法:让 C 向 Lua 注册一个特殊的钩子,该钩子在操作之间被调用,就像调试钩子一样。但是,这个钩子不同
- 它不能被 Lua 脚本更改,也不能指向 Lua 函数。
- 钩子的目的是告诉 luaV_execute(通过返回值)它是否应该产生,以便 lua_pcall 或用于调用 Lua 的任何函数返回。
- 当 luaV_execute "yield" 时,它的 yield 方式与协程的 yield 方式不同,即使用此钩子进行 yield 不会干扰协程的使用。

我的意思是,我们应该能够使用上面描述的“调试钩子”方法,但没有实际调试钩子的缺点。C 程序员可以完全控制 Lua 何时停止阻塞。例如:每 100 次操作;每次操作;从不;... 等等。

这种方法可能需要对 Lua API 进行一些更改。C 程序必须能够从 Lua “yield” 的地方恢复 Lua,但可能不能使用以协程为中心的 lua_resume 函数。似乎让协程参与进来是个坏主意,因为它可能会阻止 Lua 脚本使用协程。


如果这个功能提案没有得到任何关注,我已经找到了自己的解决方案:Windows Fibers。这是我目前找到的最干净、最安全的方法,但它只适用于 Windows。此外,您必须对 Lua 源代码进行 Windows 特定的更改。由于示例的大小,它位于单独的页面上:NonBlockingLuaExecutionWithWindowsFibers


另一个 Lua 用户需要非阻塞 Lua 执行:[3]。我觉得我应该发起一个请愿。;)


我认为 [debug.sethook] 可以用于此(另见 PIL https://www.lua.ac.cn/pil/23.2.html)。这种逐行中断的方式可以用于实现 Lua 调试器等功能。--DavidManura

我认为调试钩子不是一个好的解决方案。我查看了聊天存档,我读到的第一条消息是 [4] 中的消息。Sittig 先生担心 Lua 是否可以从钩子内部干净地终止,以及如果脚本自行更改调试钩子会发生什么。主要问题是调试钩子是从 Lua 内部调用的;C 程序应该驱动 Lua,而不是相反。

我与 RiciLake 讨论了 luaV_execute 中的 while 循环。从您的代码中迭代调用 luaV_execute,然后删除该 while 循环是一个显而易见的方法,但问题区域是 luaV_execute 是可重入的(递归的),因此您还需要消除该递归(也许是堆栈方法?)以防止递归调用阻塞太长时间。--DavidManura

RecentChanges · preferences
edit · history
最后编辑于 2006 年 9 月 10 日上午 9:12 GMT (diff)