python - 在不同的事件循环中竞速两个任务
问题描述
我正在使用 Docker SDK,并且我正在尝试将一个在几秒钟后超时的任务与另一个等待 Docker 容器完成的任务竞争。实际上,我想知道给定容器是否在我设置的超时时间内完成。
我有以下代码可以做到这一点(改编自这篇文章):
container = # ... create container with Docker SDK
timeout = # ... some int
killed = None
# our tasks
async def __timeout():
await asyncio.sleep(timeout)
return True
async def __run():
container.wait()
return False
# loop and runner
wait_loop = asyncio.new_event_loop()
done, pending = wait_loop.run_until_complete(
asyncio.wait({__run(), __timeout()}, return_when=asyncio.FIRST_COMPLETED)
)
# result extraction
for task in done:
if killed is None:
killed = task.result()
# ... do something with result
# clean up
for task in pending:
task.cancel()
with contextlib.suppress(asyncio.CancelledError):
wait_loop.run_until_complete(task)
wait_loop.close()
不幸的是,我不断收到以下错误:
File "/usr/lib/python3.5/asyncio/base_events.py", line 387, in run_until_complete
return future.result()
File "/usr/lib/python3.5/asyncio/futures.py", line 274, in result
raise self._exception
File "/usr/lib/python3.5/asyncio/tasks.py", line 241, in _step
result = coro.throw(exc)
File "/usr/lib/python3.5/asyncio/tasks.py", line 347, in wait
return (yield from _wait(fs, timeout, return_when, loop))
File "/usr/lib/python3.5/asyncio/tasks.py", line 430, in _wait
yield from waiter
File "/usr/lib/python3.5/asyncio/futures.py", line 361, in __iter__
yield self # This tells Task to wait for completion.
RuntimeError: Task <Task pending coro=<wait() running at /usr/lib/python3.5/asyncio/tasks.py:347> cb=[_run_until_complete_cb() at /usr/lib/python3.5/asyncio/base_events.py:164]> got Future <Future> pending> attached to a different loop
似乎我无法与等待任务竞争,因为它属于不同的循环。有什么办法可以绕过这个错误,以便我可以确定哪个任务首先完成?
解决方案
问题很简单,每个线程都有一个默认循环。由 设置asyncio.set_event_loop(loop)
。然后你可以通过loop = asyncio.get_event_loop()
.
所以问题是,大多数情况下,一些包asyncio.get_event_loop()
默认使用来获取当前的运行循环。举aiohttp
个例子:
class aiohttp.ClientSession(*, connector=None, loop=None, cookies=None, headers=None, skip_auto_headers=None, auth=None, json_serialize=json.dumps, version=aiohttp.HttpVersion11, cookie_jar=None, read_timeout=None, conn_timeout=None, timeout=sentinel, raise_for_status=False, connector_owner=True, auto_decompress=True, requote_redirect_url=False, trust_env=False, trace_configs=None)
如您所见,它接受loop
参数来指定运行循环。但是您也可以将其留空以asyncio.get_event_loop()
默认使用。
您的问题是您正在新创建的循环中启动协程。但是您无法确认您所有的内部操作也都在使用这个新创建的操作。正如他们可能使用的那样asyncio.get_event_loop()
,它们将被附加到另一个循环中,这是当前线程中的默认循环。
就我而言,您并不需要创建一个新的,而是让用户这样做。就像上面的例子一样,你接受一个参数loop
,如果是None
,使用默认的。
或者您需要仔细检查您的代码,以确保每个可能的协程都在使用您创建的循环。
推荐阅读
- angular - 如何将类输入属性绑定到 Angular 中组件的动画文件?
- python - 给定概率生成二元结果随机结果
- visual-studio - 将 clang 与 pass 集成到 Visual Studio
- python - 替换数组中的行数时如何停止小数变为整数?
- google-app-engine - Google Cloud Api Gateway - {"message":"no healthy upstream","code":503}
- python - Python:形成一个以一维列表为列的表
- r - 如何在R中按组对变量求和
- python - 使用 Psycopg2 将 PostgreSQL 查询结果导出为 .SQL 插入
- c# - 计算并行异步请求的延迟
- arrays - 当另一个 ARRAY 中还有一个 ARRAY 时,如何在不使用 UNNEST 的情况下使用 ARRAY 函数?