在Asyncio中,您可以将服务拆分为三个单独的任务,每个任务都有自己的循环和时间安排-您可以将它们视为三个线程,但它们都安排在同一线程中,并且通过挂起
await
.
为此,让我们从一个调用函数并定期检查其结果的实用函数开始:
async def at_interval(f, check, seconds):
while True:
feedback = f()
if check(feedback):
return feedback
await asyncio.sleep(seconds)
这个
return
等于
break
在您的原始代码中。
在这种情况下,服务生成三个这样的循环,并等待它们中的任何一个完成。无论哪一个先完成,我们都会收到我们等待的“反馈”,我们可以处理掉其他的。
async def service():
loop = asyncio.get_event_loop()
t1 = loop.create_task(at_interval(f1, check1, 3))
t2 = loop.create_task(at_interval(f2, check2, 5))
t3 = loop.create_task(at_interval(f3, check3, 7))
done, pending = await asyncio.wait(
[t1, t2, t3], return_when=asyncio.FIRST_COMPLETED)
for t in pending:
t.cancel()
feedback = await list(done)[0]
do_cleanup(feedback)
asyncio.get_event_loop().run_until_complete(service())
这和您的代码之间的一个小区别是,这里有可能(尽管可能性很小)在
service
拿起它。例如,如果通过一次倒霉的行程,上述两个任务最终共享唤醒的绝对时间到微秒,那么它们将被安排在相同的事件循环迭代中。两者都将从各自对应的
at_interval
协程,以及
done
将包含多个反馈。代码通过选择反馈并调用
do_cleanup
在那一个,但它也可以循环所有。
如果这是不可接受的,你可以很容易地通过每一个
阿特氏间期
取消除自身以外的所有任务的可调用文件。此操作当前在中完成
服务
为了简洁,但可以在
阿特氏间期
也。一个任务取消另一个任务将确保只能存在一个反馈。