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

Python多进程与多asyncio事件循环的用法是否正确?

多进程与asyncio事件循环用法分析

问题背景

通过multiprocessing.Process启动3个进程,每个进程运行一组异步任务,期望利用多核CPU同时发挥asyncio的异步特性。但运行后日志显示,虽进程ID不同,却似乎共用同一线程/事件循环。

入口程序main.py

import asyncio
from loguru import logger
from multiprocessing import Process
from app.events import type_a_tasks, type_b_tasks, type_c_tasks


def run_task(task):
    loop = asyncio.get_event_loop()
    loop.run_until_complete(task())
    loop.run_forever()


def main():
    processes = list()
    processes.append(Process(target=run_task, args=(type_a_tasks,)))
    processes.append(Process(target=run_task, args=(type_b_tasks,)))
    processes.append(Process(target=run_task, args=(type_c_tasks,)))

    for process in processes:
        process.start()
        logger.info(f"Started process id={process.pid}, name={process.name}")

    for process in processes:
        process.join()


if __name__ == '__main__':
    main()

异步任务示例type_a_tasks

import asyncio
from . import business_1, business_2, business_3, business_4, business_5, business_6


async def type_a_tasks():
    tasks = list()
    tasks.append(asyncio.create_task(business_1.main()))
    tasks.append(asyncio.create_task(business_2.main()))
    tasks.append(asyncio.create_task(business_3.main()))
    tasks.append(asyncio.create_task(business_4.main()))
    tasks.append(asyncio.create_task(business_5.main()))
    tasks.append(asyncio.create_task(business_6.main()))

    await asyncio.wait(tasks)
    return tasks

问题分析与修正

1. 代码中的冗余与逻辑问题

  • loop.run_forever()完全多余:loop.run_until_complete(task())会一直阻塞到type_a_tasks执行完毕。如果business_*是长期运行的异步任务(比如持续监听消息),await asyncio.wait(tasks)会一直挂起,run_until_complete永远不会返回,run_forever()根本没机会执行;如果business_*是一次性任务,run_until_complete执行完后事件循环已无任务,run_forever()会让空循环一直跑,毫无意义。
  • 事件循环创建方式不够规范:Python 3.7+推荐使用asyncio.run()替代手动管理事件循环,它会自动创建新循环、运行任务、执行后关闭循环,避免手动操作的潜在问题。

2. “同一线程/事件循环”的误解

不同进程的线程ID是进程内独立编号,不同进程的主线程ID可能完全相同,但它们属于不同进程,是完全独立的执行环境,各自拥有独立的事件循环。你看到的“同一线程ID”只是进程内的编号重复,并非真的共用线程/循环。可以通过完善日志格式确认:

# 在main.py开头添加日志格式配置
logger.add(sys.stderr, format="{time} | 进程ID:{process.id} | 线程ID:{thread.id} | {level} | {message}")

修正后的代码

修正run_task函数

def run_task(task):
    # 用asyncio.run自动管理事件循环,替代手动操作
    asyncio.run(task())

如果business_*是长期运行的任务(无需type_a_tasks返回),可以简化type_a_tasks:

async def type_a_tasks():
    tasks = [
        asyncio.create_task(business_1.main()),
        asyncio.create_task(business_2.main()),
        asyncio.create_task(business_3.main()),
        asyncio.create_task(business_4.main()),
        asyncio.create_task(business_5.main()),
        asyncio.create_task(business_6.main()),
    ]
    # 等待所有任务完成(如果是长期任务,此调用会一直阻塞)
    await asyncio.gather(*tasks)

最终结论

你的多进程+asyncio的核心思路是正确的——通过多进程利用多核,每个进程内用asyncio处理IO密集型异步任务,完全符合场景需求。只需修正代码中的冗余逻辑,并通过日志格式区分进程/线程ID即可消除误解。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 21:40:26