如何超时asyncio.to_thread?

How to timeout asyncio.to_thread?

我在 Python 3.9 中对 new asyncio features 进行了试验,得到了以下代码:

import asyncio

async def inc(start):
    i = start
    while True:
        print(i)
        i += 2
    return None

async def main():
    x = asyncio.gather(
        asyncio.to_thread(inc, 0),
        asyncio.to_thread(inc, 1)
    )
    try:
        await asyncio.wait_for(x, timeout=5.0)
    except asyncio.TimeoutError:
        print("timeout!")

asyncio.run(main())

我的期望是该程序将从 0 开始打印数字并在 5 秒后终止。但是,当我执行程序 here 时,我没有看到任何输出和以下警告:

/usr/lib/python3.9/asyncio/events.py:80: RuntimeWarning: coroutine 'inc' was never awaited
  self._context.run(self._callback, *self._args)
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
/usr/lib/python3.9/concurrent/futures/thread.py:85: RuntimeWarning: coroutine 'inc' was never awaited
  del work_item
RuntimeWarning: Enable tracemalloc to get the object allocation traceback

asyncio.to_thread 常规 函数转换为协程。

您只需将 async def inc 更改为 def inc。可以这样做,因为没有await,不是真正的协程

但是,您不能终止线程。超时会导致停止等待,而不是停止计算数字。

更新:详细来说,asyncio.gather 等待协程直到超时。当超时取消时,gather 取消所有仍然 运行 协程 a 并等待它们终止。取消协程意味着在最近的 await 语句处传递异常。在这种情况下,没有 await 并且协程永远不会收到取消异常。程序在那一点挂起。