You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用`run_in_executor`创建任务未显式等待,为何Python进程仍会等待任务完成?

你的预期没错,但得先搞懂run_in_executor背后的线程池逻辑

首先直接给结论:你的预期(进程在打印main finished后立即退出)是合理的,但默认情况下asyncio的行为会阻止这种情况发生,而你提到的loop.run_until_complete(loop.shutdown_default_executor())确实是解决这个问题的正确方式。

为什么进程没有立即退出?

当你调用loop.run_in_executor(None, sync_sleep, 4)时,asyncio会使用默认的ThreadPoolExecutor来执行同步函数。这个线程池里的线程默认是非守护线程——在Python中,主线程结束时,非守护线程会继续运行直到任务完成,才会让整个进程退出。

所以即使你的事件循环已经通过run_until_complete(main())执行完毕(打印了main finished),executor里的线程还在后台跑sync_sleep(4),进程必须等这个线程任务结束才会终止,这就是为什么你会看到sync_sleep awake在main finished之后打印。

你的解决方案是对的!

添加loop.run_until_complete(loop.shutdown_default_executor())确实能让事件循环等待默认executor中所有已提交的任务完成。修改后的代码示例如下:

import asyncio
import time

def sync_sleep(x):
    print("sync_sleep going to sleep")
    time.sleep(x)
    print("sync_sleep awake")

async def main():
    loop = asyncio.get_running_loop()
    loop.run_in_executor(None, sync_sleep, 4)
    print("main going to sleep")
    await asyncio.sleep(1)
    print("main awake ")

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    try:
        loop.run_until_complete(main())
        # 等待默认executor的所有任务执行完成
        loop.run_until_complete(loop.shutdown_default_executor())
    finally:
        loop.close()
    print("main finished")

执行这段代码的输出会变成:

sync_sleep going to sleep
main going to sleep
main awake 
sync_sleep awake
main finished

此时进程会在打印main finished后立即退出,因为executor已经关闭,所有后台任务都已完成。

额外选项:不想等待同步任务完成怎么办?

如果你的需求是让进程在main结束后直接退出,不管sync_sleep是否完成,可以自定义一个使用守护线程的executor:

import asyncio
import time
from concurrent.futures import ThreadPoolExecutor

def sync_sleep(x):
    print("sync_sleep going to sleep")
    time.sleep(x)
    print("sync_sleep awake")

async def main():
    loop = asyncio.get_running_loop()
    # 创建使用守护线程的executor
    daemon_executor = ThreadPoolExecutor(thread_name_prefix="Daemon", daemon=True)
    loop.run_in_executor(daemon_executor, sync_sleep, 4)
    print("main going to sleep")
    await asyncio.sleep(1)
    print("main awake ")

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    try:
        loop.run_until_complete(main())
    finally:
        loop.close()
    print("main finished")

这种情况下,主线程结束时会强制终止守护线程,进程会立即退出,sync_sleep awake大概率不会被打印(取决于线程是否来得及执行到那一步)。

内容的提问来源于stack exchange,提问作者adnanmuttaleb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 09:07:43