使用协程进行事件处理的正确方法是什么?

时间:2012-07-24 01:05:38

标签: events lua coroutine

我正在试图弄清楚如何使用协同程序处理事件(在Lua中)。我看到一种常见的做法似乎是创建包装函数,产生当前的协程,然后在你等待的东西发生时恢复它。这似乎是一个很好的解决方案,但这些问题呢? :

  1. 你如何同时等待多个事件,而分支取决于哪一个先来?或者是否应该重新设计程序以避免这种情况?

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

  3. 如何触发协程从外部改变其状态?例如,我想要一个函数,当被调用时,会导致协程跳转到另一个步骤,或者开始等待不同的事件。

  4. 编辑:

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

    我只是想知道这是否被认为是使用协程进行事件处理的正确方法。例如,如果我有一个读事件和一个计时器事件(作为读取的超时),并且首先发生读事件,我必须手动取消计时器。它似乎不符合顺序性或处理事件与协同程序。

1 个答案:

答案 0 :(得分:4)

  

你如何同时等待多个事件,并根据哪个事件先来分支?

如果你需要使用协同程序,而不仅仅是你注册的Lua函数(例如,如果你有一个函数做东西,等待一个事件,然后做更多的东西),那么这很简单。当协同程序恢复时,coroutine.yield将返回传递给coroutine.resume的所有值。

所以只需传递事件,然后让脚本自行决定是否等待它。实际上,您可以构建一个简单的函数来执行此操作:

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

  do
    RegisterForAnyEvent(coroutine.running()) --Registers the coroutine with the system, so that it will be resumed when an event is fired.
    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函数。或者你可以设计你的等待状态以便能够跳过。或者其他什么。