如何使用协程来处理事件?

我正在尝试使用 coroutines(在 Lua 中)处理事件。我看到常见的做法似乎是创建包装函数,在等待事情发生时暂停当前 coroutine,然后在发生等待的事情时恢复它。这似乎是一个不错的解决方案,但以下问题该如何处理?:

  1. 如何同时等待多个事件,并根据哪个事件先发生分支?或者应该重新设计程序以避免这种情况?

  2. 在一定时间后如何取消等待?事件循环可以在其 socket 发送/接收包装器中具有超时参数,那么自定义事件呢?

  3. 如何从外部触发 coroutine 更改其状态?例如,我希望一个函数在调用时会导致 coroutine 跳转到不同的步骤,或开始等待其他事件。

编辑:

目前我有一个系统,其中我为事件注册一个 coroutine,并在每次事件发生时使用事件名称和信息作为参数恢复 coroutine。使用此系统,1 和 2 不是问题,并且可以通过让 coro 期望一个特殊的事件名称来解决 3,该特殊事件名称使其跳转到不同的步骤,并用该名称作为参数恢复 coroutine。此外,自定义对象可以以相同的方式使用方法来注册事件处理程序。

我只是想知道这是否被认为是使用 coroutines 处理事件的正确方式。例如,如果我有一个读取事件和一个计时器事件(作为读取的超时),并且读取事件先发生,那么我必须手动取消计时器。它似乎并不适合使用 coroutines 处理事件的顺序性质。

点赞
用户734069
用户734069

如何在等待多个事件时进行分支并根据哪一个事件首先发生进行操作?

如果需要使用协程来实现,而不仅仅是注册一个 Lua 函数(例如,如果您有一个函数可以执行某些操作,等待事件,然后再执行其他操作),那么这是相当简单的。 coroutine.yield 将在恢复协程时返回由 coroutine.resume 传递的所有值。

所以只需传递事件,让脚本自行决定是否等待该事件即可。确实,您可以构建一个简单的函数来实现:

function WaitForEvents(...)
  local events = {...}
  assert(#... ~= 0, "You must pass at least one parameter")

  do
    RegisterForAnyEvent(coroutine.running()) --将协程注册到系统中,以便在事件触发时恢复协程。
    local event = coroutine.yield()
    for i, testEvt in ipairs(events) do
      if(event == testEvt) then
        return
      end
    end
  until(false)
end

此函数将持续等待,直到给定的事件之一被触发。该循环假设 RegisterForAnyEvent 是临时的,仅为一个事件注册该函数,因此您需要在每个事件触发时重新注册。

如何在一定时间后取消等待?

在上述循环中加入一个计数器,并在一定时间后跳出循环即可。我留这个给读者练习;这完全取决于您的应用程序如何测量时间。

如何从外部触发协程以改变其状态?

您无法将 Lua 函数变成不同的“状态”。您只能调用函数并让它们返回结果。因此,如果要跳过某些过程中的某些步骤,必须编写您的 Lua 函数系统以使其可跳过。

如何实现取决于您。您可以将每组非等待命令作为单独的 Lua 函数。或者你可以设计等待状态以便跳过。或者别的什么。

2012-07-24 01:34:22