python快速入门学习笔记(进阶篇)三十八:多进程 vs 多线程,该如何选择?

  • 原创
  • 作者:程序员三丰
  • 发布时间:2026-06-06 11:03
  • 浏览量:7
Python入门第三十八课,主要介绍在实际开发中,面对具体开发场景时,如何选择多进程还是多线程。

选择原则

多进程与多线程的选择核心取决于任务类型:I/O密集型任务优先使用多线程,CPU密集型任务优先使用多进程。

这一原则源于两者在资源隔离性、通信成本和调度开销上的本质差异。下文从不同关键维度进行展开分析。

本质区别:为什么选择逻辑不同?

1、资源与隔离性

  • 多进程:每个进程拥有独立内存空间和资源系统,进程间严格隔离。一个进程崩溃不会影响其他进程,但资源占用高、通信需通过IPC(如管道、内存共享),开销较大。
  • 多线程:线程共享所属进程的内存和资源,通信直接通过共享变量,无需序列化。但一个线程崩溃可能导致整个进程终止,隔离性较弱。

2、调度与开销

  • 进程切换:需保存/恢复整个地址空间,开销高(微秒级)。
  • 线程切换:仅需切换栈和寄存器,开销低(纳米级),适合高频切换场景。

关键场景选择指南

1、优先选择多线程的场景

① I/O 密集型任务

典型场景:网络请求(爬虫、API调用)、文件读写、数据库操作、消息队列消费。

原因:任务大部分时间在等待I/O响应(如网络延迟、磁盘读写),线程在等待时会释放CPU资源,其他线程可立即执行,高效掩盖I/O延迟。

案例:10个网页爬取任务,多线程耗时约2秒(并发等待),单线程需10秒。

② 需频繁共享数据的轻量任务

典型场景:GUI程序(界面响应+后台数据加载)、实时统计计数。

原因:线程共享内存,通信无需序列化,避免了IPC开销。但需要通过锁(如thread.Lock)保证线程安全。

2、优先选择多进程的场景

① CPU 密集型任务

典型场景:数值计算(矩阵运算、质数判断)、图像/视频处理、AI模型推理。

原因:多进程绕过GIL限制(如Python中),真正利用多核并行计算。多线程在此类任务中因GIL竞争,效率甚至低于单线程。

案例:4核机器上并行计算10的7次方,多进程耗时约为单核的1/4,而多线程耗时接近单核。

② 高可靠性要求的系统

典型场景:浏览器标签页、沙箱环境、关键服务(如Nginx Worker进程)。

原因:进程隔离性强,单个进程崩溃不影响全局,适合容错性要求高的系统。

案例演示:CPU密集型任务,更适合用多进程

import time
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor


# CPU 密集型任务
def cpu_task(n):
    print(f'任务{n}开始了')
    total = 0
    for i in range(10_000_000):
        total += i * i
    return total


if __name__ == '__main__':
    # print('====== 多进程完成【CPU密集型任务】 ======')
    start = time.time()
    # 开启四个进程进行计算
    with ProcessPoolExecutor(4) as executor:
        list(executor.map(cpu_task, [1, 2, 3, 4]))
    end = time.time() - start
    print(f'多进程总耗时:{end}秒') # 1.2344918251037598秒

    # print('====== 多线程完成【CPU密集型任务】 ======')
    # start = time.time()
    # # 开启四个线程进行计算
    # with ThreadPoolExecutor(4) as executor:
    #     list(executor.map(cpu_task, [1, 2, 3, 4]))
    # end = time.time() - start
    # print(f'多线程总耗时:{end}秒') # 2.694937229156494秒

从代码运行结果看,CPU密集型任务多进程确实比多线程效率高。

案例演示:IO密集型任务,更适合用多线程

import time
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor


# 拷贝文件
def copy_file(index):
    with open('./media/demo.mp4', 'rb') as source, open(f'./media/demo_副本{index}.mp4', 'wb') as target:
        while True:
            data = source.read(1024 * 1024)  # 每次读 1MB
            if not data:
                break
            target.write(data)


if __name__ == '__main__':
    # print('====== 使用多进程完成【IO密集型任务】 ======')
    # start = time.time()
    # with ProcessPoolExecutor(4) as executor:
    #     for i in range(4):
    #         executor.submit(copy_file, i)
    # end = time.time() - start
    # print(f'多进程耗时:{end}秒') # 2.1582999229431152秒

    print('====== 使用多线程完成【IO密集型任务】 ======')
    start = time.time()
    with ThreadPoolExecutor(4) as executor:
        for i in range(4):
            executor.submit(copy_file, i)
    end = time.time() - start
    print(f'多线程耗时:{end}秒') # 1.9817359447479248秒

从代码运行结果看,IO密集型任务多进程和多线程效率相差不大,但是多进程开销大。

最终建议

没有绝对最优方案,需要根据任务特性、资源约束和语言环境综合权衡。对关键系统,务必通过实际测试验证选择。

声明:本文为原创文章,51blog.xyz和作者拥有版权,如需转载,请注明来源于51blog.xyz并保留原文链接:https://www.51blog.xyz/article/140.html

文章归档

推荐文章

buildadmin logo
Thinkphp8 Vue3 Element PLus TypeScript Vite Pinia

🔥BuildAdmin是一个永久免费开源,无需授权即可商业使用,且使用了流行技术栈快速创建商业级后台管理系统。

热门标签

PHP ThinkPHP ThinkPHP5.1 Go Mysql Mysql5.7 Redis Linux CentOS7 Git HTML CSS CSS3 Javascript JQuery Vue LayUI VMware Uniapp 微信小程序 docker wiki Confluence7 学习笔记 uView ES6 Ant Design Pro of Vue React ThinkPHP6.0 chrome 扩展 翻译工具 Nuxt SSR 服务端渲染 scrollreveal.js ThinkPHP8.0 Mac webman 跨域CORS vscode GitHub ECharts Canvas vue3 three.js 微信支付 PHP全栈开发 Python AI 人工智能 AI生成 工作经验 实战笔记