Events 什么';使用协程进行事件处理的正确方法是什么?
我试图弄清楚如何使用协同路由(在Lua中)处理事件。我看到一种常见的方法似乎是创建包装器函数,生成当前的协程,然后在等待的事情发生时恢复它。这似乎是一个很好的解决方案,但这些问题呢Events 什么';使用协程进行事件处理的正确方法是什么?,events,lua,coroutine,Events,Lua,Coroutine,我试图弄清楚如何使用协同路由(在Lua中)处理事件。我看到一种常见的方法似乎是创建包装器函数,生成当前的协程,然后在等待的事情发生时恢复它。这似乎是一个很好的解决方案,但这些问题呢 如何在同一时间等待多个事件,并根据哪个事件先发生而进行分支?还是应该重新设计程序以避免这种情况 一段时间后如何取消等待?事件循环的套接字发送/接收包装中可以有超时参数,但是自定义事件呢 如何触发协同程序从外部更改其状态?例如,我想要一个函数,当被调用时,它会导致协同路由跳转到不同的步骤,或者开始等待不同的事件 编辑:
我只是想知道这是否被认为是使用协程进行事件处理的正确方法。例如,如果我有一个读取事件和一个计时器事件(作为读取的超时),并且读取事件首先发生,我必须手动取消计时器。它似乎不符合顺序性质,也不适合用协同程序处理事件 如何在同一时间等待多个事件,并根据哪个事件先发生而进行分支 如果您需要为此使用协程,而不仅仅是注册一个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函数。或者,您可以将等待状态设计为能够提前跳过。或者随便什么。我现在就是这样做的,但我看到大多数示例(和库,如COPA)使用生成包装来阻止函数,而不是注册事件函数,然后手动调用
yield
。我的问题是如何解决这种类型的协同程序事件系统的问题,因为据我所知,它看起来更优雅,而且是“正确”的方式(如果不是,请纠正我)。@mtk358:然后你将此代码放入包装器中。这不是火箭科学。如果您有等待多个事件的东西,那么无论什么“生成包装器”都应该有等待多个事件的代码。我知道“生成包装器”一次只能等待一个事件,但我要求可能应该避免这种情况,并以不同的方式编写(但如何编写?)。最让我感到疑惑的是,Copas使用了“屈服包装器”,似乎完全忽略了我的三个问题。但它还是必须要有某种可用性,对吗?@mtk358:这个Copas库的文档是否说您可以等待多个事件?如果不允许,那么它就是不允许(或者您必须自己编写代码)。而且,我从来没有说过不能使用屈服包装等待多个事件;事实上,我说的恰恰相反。您只需向包装器提供多个事件,如上所示。事实上,这是一个令人满意的包装器。“我只是想知道这是否被认为是使用协程进行事件处理的正确方式。”如果它对您有效,那么它就是正确的方式。为什么要使用计时器事件来超时另一个事件?简单地在你的活动系统中加入超时不是更有意义吗?“如果它对你有效,那么它是正确的方式”它工作正常(但不是很好),我想可能有一种方式更好,但我错过了它,因为我不太熟悉协同活动。“为什么要使用计时器事件来超时另一个事件?”。我可以,但是自定义事件源都必须实现超时。也许我可以通过添加一个系统来向主事件循环注册自定义事件源来解决这个问题?最后,也许我应该在第一次触发时自动删除处理程序?