任务添加到不同线程中的空循环时的奇怪行为

问题描述 投票:2回答:2

我有一个应用程序,它将协同程序添加到已经运行的事件循环中。这些协同程序的参数依赖于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是标准的,为什么空案例会成为问题?

python python-asyncio
2个回答
6
投票

在运行后将任务添加到event_loop是标准的,为什么空案例会成为问题?

因为你应该从运行事件循环的线程中添加任务。通常,除了通过为此目的设计的API(例如loop.run_in_executor)之外,不应混合线程和asyncio。

如果您理解这一点并且仍然有充分的理由从单独的线程添加任务,请使用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不是线程安全的,因此如果它与正在运行的事件循环并行执行,则可能存在任意数量的竞争条件。


1
投票

因为loop.create_task不是线程安全的,如果你设置loop._debug = True,你应该看到错误为

Traceback (most recent call last): File "test.py", line 23, in <module> loop.create_task(bar("secondary task")) File "/Users/soulomoon/.pyenv/versions/3.6.3/lib/python3.6/asyncio/base_events.py", line 284, in create_task task = tasks.Task(coro, loop=self) File "/Users/soulomoon/.pyenv/versions/3.6.3/lib/python3.6/asyncio/base_events.py", line 576, in call_soon self._check_thread() File "/Users/soulomoon/.pyenv/versions/3.6.3/lib/python3.6/asyncio/base_events.py", line 615, in _check_thread "Non-thread-safe operation invoked on an event loop other " RuntimeError: Non-thread-safe operation invoked on an event loop other than the current one

© www.soinside.com 2019 - 2024. All rights reserved.