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

2024-01-06

我看到 @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 中的传统多线程相同吗?那么以这种方式使用线程有什么好处呢?


源代码 https://github.com/python/cpython/blob/master/Lib/asyncio/threads.py of to_thread很简单。归根结底就是等待在执行器中运行 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor使用默认执行器(executor论点是None) 这是线程池执行器 https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor.

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

另请注意,该函数在当前任务的上下文中运行,因此它的上下文变量 https://docs.python.org/3/library/contextvars.html值将在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)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

asyncio.to_thread() 方法与 ThreadPoolExecutor 不同吗? 的相关文章

随机推荐