2012-07-24 45 views
2

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

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

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

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

编辑:

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

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

+0

“我只是想知道这是否被认为是使用协程进行事件处理的正确方法。”如果它适合你,那么这是正确的方式。为什么你会使用一个计时器事件来暂停另一个事件?简单地在您的事件系统中内置超时是否更有意义? – 2012-07-24 18:57:24

+0

“如果它对你有用,那么它是正确的方式”它工作正常(但不是很好),我认为可能有更好的方法,但我错过了它,因为我不是非常与协程的家族。 “你为什么要使用计时器事件来暂停另一个事件?”。我可以,但自定义事件源将都必须实现超时。也许我可以通过添加一个系统来使用主事件循环注册自定义事件源来解决这个问题?最后,也许我应该让处理程序在第一次触发时自动删除? – mtk358 2012-07-24 19:22:34

回答

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函数。或者你可以设计你的等待状态,以便能够跳过。管他呢。

+0

这就是我现在这样做的方式,但是我发现大多数示例(和库,例如Copas)使用yielding包装来阻塞函数,而不是事件注册函数,然后手动调用yield。我的问题是,我怎样才能解决我在协程事件系统中遇到的问题,因为据我所知,它看起来更加优雅,并且是“正确”的方式(如果不是,请纠正我)。 – mtk358 2012-07-24 12:08:06

+0

@ mtk358:然后你把这段代码放在包装中。这不是火箭科学。如果你有一些事情要等待多个事件,那么无论“产生包装器”都应该让代码等待多个事件。 – 2012-07-24 18:59:15

+0

我知道“屈服包装”一次只能等待一个事件,但我问过这种情况应该避免并写成不同的方式(但是怎么做?)。让我对此产生疑惑的主要原因是Copas使用“让步包装”,并且似乎完全忽视了我的三个问题。但它仍然必须以某种方式可用,对吧? – mtk358 2012-07-24 19:26:25

相关问题