asyncio.to_thread()方法与ThreadPoolExecutor不同吗?

我看到 @python 3.9+ 添加了 asyncio.to_thread() 方法,它的描述说它在单独的线程上运行阻塞代码以立即运行。见下面的例子:

def blocking_io():
    print(f"start blocking_io at {time.strftime('%X')}")
    # Note that time.sleep() can be replaced with any blocking
    # IO-bound operation, such as file operations.
    time.sleep(1)
    print(f"blocking_io complete at {time.strftime('%X')}")

async def main():
    print(f"started main at {time.strftime('%X')}")

    await asyncio.gather(
        asyncio.to_thread(blocking_io),
        asyncio.sleep(1))

    print(f"finished main at {time.strftime('%X')}")


asyncio.run(main())

# Expected output:
#
# started main at 19:50:53
# start blocking_io at 19:50:53
# blocking_io complete at 19:50:54
# finished main at 19:50:54

通过解释,它似乎使用线程机制而不是上下文切换或协程。这是否意味着它实际上并不是异步的?它与concurrent.futures.ThreadPoolExecutor中的传统多线程相同吗?那么这样使用线程有什么好处呢?

回答

源代码的to_thread非常简单。它归结为等待run_in_executor带有默认执行程序(执行程序参数是None),即ThreadPoolExecutor。

事实上,是的,这是传统的多线程,旨在在单独线程上运行的 ode 不是异步的,但to_thread允许您await异步获取其结果。

另请注意,该函数在当前任务的上下文中运行,因此其上下文变量值将在func.

async def to_thread(func, /, *args, **kwargs):
    """Asynchronously run function *func* in a separate thread.
    Any *args and **kwargs supplied for this function are directly passed
    to *func*. Also, the current :class:`contextvars.Context` is propogated,
    allowing context variables from the main thread to be accessed in the
    separate thread.
    Return a coroutine that can be awaited to get the eventual result of *func*.
    """
    loop = events.get_running_loop()
    ctx = contextvars.copy_context()
    func_call = functools.partial(ctx.run, func, *args, **kwargs)
    return await loop.run_in_executor(None, func_call)


以上是asyncio.to_thread()方法与ThreadPoolExecutor不同吗?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>