非阻塞 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 函数。
- 钩子的目的是通过返回码告诉 `luaV_execute` 是否应该让出(yield),以便 `lua_pcall` 或用于调用 Lua 的任何函数都能返回。
- 当 `luaV_execute` "让出" 时,它以一种不同于协程让出(yield)的方式让出,即,使用此钩子让出不应以任何方式干扰协程的使用。

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

这种方法可能涉及对 Lua API 的一些更改。C 程序必须能够从“让出”的地方恢复 Lua,但可能不是使用以协程为中心的 `lua_resume` 函数。让协程介入似乎是个坏主意,因为它可能会排除 Lua 脚本使用协程。


我找到了一个解决方案,如果这个功能提案从未受到关注,我将使用它:Windows Fibers。这是我目前找到的完成此任务的最清晰、最安全的方法,但它仅在 Windows 上有效。此外,您必须对 Lua 源代码进行特定于 Windows 的更改。由于示例的篇幅,它在单独的页面上:NonBlockingLuaExecutionWithWindowsFibers


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


我认为 [debug.sethook] 可用于此目的(另请参阅 PIL https://lua.ac.cn/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 日 上午 3:12 GMT (diff)