我有一个将协程添加到已经运行的事件循环中的应用程序。这些协程的参数取决于I / O,并且在我最初启动事件循环(使用loop.run_forever())时不可用,因此稍后再添加任务。为了演示这种现象,下面是一些示例代码:
import asyncio
from threading import Thread
from time import sleep
loop = asyncio.new_event_loop()
def foo():
loop.run_forever()
async def bar(s):
while True:
await asyncio.sleep(1)
print("s")
#loop.create_task(bar("A task created before thread created & before loop started"))
t = Thread(target=foo)
t.start()
sleep(1)
loop.create_task(bar("secondary task"))
奇怪的行为是,当调用loop.run_forever()时,如果循环中至少有一个任务,那么一切都会按预期进行。即,当注释行未注释掉时。
但是,当它被注释掉时,如上所示,什么也没有打印,看来我无法向event_loop添加任务。我应该避免在不添加单个任务的情况下调用run_forever()吗?我不明白为什么这应该是一个问题。在event_loop运行之后向其添加任务是标准的,为什么空情况会成为问题?
在event_loop运行之后向其添加任务是标准的,为什么空情况会成为问题?
因为您应该从运行事件循环的线程中添加任务。通常,除非通过为此目的设计的API,否则不要混用线程和异步loop.run_in_executor
。
如果您理解了这一点,但仍然有充分的理由从单独的线程中添加任务,请使用asyncio.run_coroutine_threadsafe
。更改loop.create_task(bar(...))
为:
asyncio.run_coroutine_threadsafe(bar("in loop"), loop=loop)
run_coroutine_threadsafe
以线程安全的方式访问事件循环,并确保事件循环唤醒以注意到新任务,即使它没有其他事情要做,并且仅在等待IO /超时。
事先添加另一个任务似乎是可行的,因为bar
碰巧是一个无限协程,它使事件循环每秒唤醒一次。一旦事件循环由于任何原因唤醒,它将执行所有可运行任务,而不管哪个线程将其添加了。但是,依赖于此将是一个非常糟糕的主意,因为loop.create_task
它不是线程安全的,因此,如果它与正在运行的事件循环并行执行,则可能存在许多竞争条件。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句