Django Multiprocessing 如何实现多进程同时运行处理并发请求
常见故障根因及修复方案
Web服务部署模型限制
若你使用的是单进程单线程的服务端(比如Flask、Django默认的开发启动模式),请求本身会被串行排队处理,即使请求逻辑中包含多进程代码,也必须等前一个请求处理完成后才会接收下一个请求。
解决方案:更换为多worker的生产级部署方式,例如用Gunicorn启动服务时添加参数--workers 4,用Uvicorn启动ASGI服务时添加参数--workers 4,让服务本身支持同时接收多个请求。进程池初始化逻辑错误
若你将multiprocessing.Pool初始化在全局位置且设置的进程数小于并行请求数,或是在请求内部反复初始化进程池并添加了阻塞等待逻辑,都会出现进程复用阻塞的问题。
解决方案分为两种:- 全局初始化一个进程数足够的进程池作为单例,所有请求复用该池提交异步任务,示例:
from multiprocessing import Pool # 全局初始化,进程数可根据服务器核心数调整 task_pool = Pool(processes=8) def handle_request(params): # 异步提交任务,不阻塞当前请求 task_pool.apply_async(your_cost_task, args=(params,)) return {"code": 0, "msg": "任务提交成功"}- 每个请求直接创建独立子进程执行任务,不共享进程池,示例:
from multiprocessing import Process def handle_request(params): p = Process(target=your_cost_task, args=(params,)) p.daemon = True # 设为守护进程,主进程退出时自动销毁 p.start() return {"code": 0, "msg": "任务提交成功"}Windows系统缺少入口保护
Windows系统下multiprocessing默认使用spawn模式启动子进程,必须在入口代码处添加if __name__ == '__main__'保护,否则会出现子进程重复导入主模块、进程启动失败的问题,示例入口代码:if __name__ == '__main__': # 所有服务启动、进程池初始化逻辑必须放在该判断内 app.run(host="0.0.0.0", port=8000)共享资源锁导致的串行假象
若你的耗时任务中存在全局共享资源(如文件、公共数据库连接、全局变量)访问逻辑且添加了互斥锁,会出现多进程启动但任务串行执行的假象。
解决方案:缩小锁的粒度,减少锁持有时间,或是为每个子进程分配独立的资源实例,避免跨进程锁竞争。
基础功能验证
你可以先运行以下最小测试脚本,确认多进程逻辑本身可以正常并行:
import time from multiprocessing import Process def test_task(task_id): print(f"任务{task_id}启动") time.sleep(3) print(f"任务{task_id}结束") if __name__ == '__main__': start_time = time.time() p_list = [Process(target=test_task, args=(i,)) for i in range(3)] for p in p_list: p.start() for p in p_list: p.join() print(f"总耗时: {time.time() - start_time:.2f}秒")
正常运行总耗时在3秒左右,若总耗时接近9秒则说明多进程逻辑本身存在问题,可根据上述方案逐一排查。
内容的提问来源于stack exchange,提问作者Ankit Gadewal

