Roblox 中的 Lua 异步调用究竟是如何工作的?

How exactly do Lua asynchronous calls in Roblox work?

我来自 Javascript 背景并且非常习惯带有回调的异步调用。还精通 Promise 和异步等待。我最近开始开发 Roblox 游戏,它的 Lua SDK 提供了一堆不需要回调的 DoSomethingAsync 函数。网上查了一些资料,人家说async调用后放弃执行控制,等结果回来再控制returns。这允许开发人员编写代码,就好像事情是同步完成的一样。有人可以验证这是不是真的?线程模型是否类似于 Javascript 解释器只有一个线程?

诚然,由于命名原因,它有点令人困惑。名称中带有异步的 API 调用是 C++ 端 的异步调用 ,主要针对 Web 服务,它们确实在 C++ 中使用回调函数。但是您没有注册来自 Lua 的回调,它们的行为就像您正在同步调用内部具有 wait() 语句的 Lua 函数一样。这些 API 调用在 wiki 上通常表示为 "YieldFunctions",因为这正是它们所做的,它们产生 Lua 线程并且不会 return 直到 C++ 回调函数被调用并将 Web 请求的结果传递回 Lua。

Lua,和JavaScript一样,一次只执行一个线程。然而,Lua 有一个叫做 coroutines 的特性,它允许不同的执行线程交错执行。 (Lua协程有点类似于JavaScriptasync函数)

coroutine.resume(thread) 将执行切换到 thread ("It's your turn now")。 coroutine.resume 的调用者将在 thread 完成或调用 coroutine.yield() ("I'm done for now, call me back later").

时重新获得控制权

Roblox 有一个 thread scheduler 来决定当当前调度的线程 产生 时哪个线程接下来进入 运行。线程在调用 wait() 或任何 yield 函数时会产生。

IO 请求在 C++ 中的单独线程中完成(就像 JavaScript)。当 IO 请求完成时,调度程序将请求 IO 的线程放在下一个要调度的队列的前面(与 Javascript 不同)。


上面的线程调度程序 link 有一个 wait() 看起来如何的示例,通过忙等待在纯 Lua 中实现。在 C++ 中,您可以使用真正的睡眠来避免 CPU 忙碌。