深入理解 Python 的多进程编程 (Multiprocessing)

在 Python 中,multiprocessing 模块提供了多进程支持,是处理并发任务的一个核心工具。与多线程不同,多进程可以突破 GIL(Global Interpreter Lock,全局解释器锁)的限制,充分利用多核 CPU 进行并行计算。本文将详细介绍 Python 中的多进程编程,包括其基础用法、进程间通信、同步机制,以及与线程和协程的对比。


一、为什么选择多进程?

1. GIL 的限制

Python 的 GIL 限制了多线程的并行能力,同一时间只能有一个线程执行 Python 字节码。对于 CPU 密集型任务,多线程不能充分利用多核 CPU。

多进程通过创建独立的进程,每个进程拥有独立的 GIL,可以并行执行任务,适合需要大量计算的场景。

2. 适用场景

  • CPU 密集型任务:如科学计算、视频处理、大量数据的复杂运算。
  • 任务隔离需求:每个进程有独立的内存空间,减少了竞争资源的风险。

二、multiprocessing 的基础用法

1. 创建子进程

使用 multiprocessing.Process 类可以轻松创建子进程。

from multiprocessing import Process
import osdef worker(task_name):print(f"Task {task_name} is running in process {os.getpid()}")if __name__ == "__main__":process1 = Process(target=worker, args=("A",))process2 = Process(target=worker, args=("B",))process1.start()process2.start()process1.join()process2.join()print("All processes completed")

输出

Task A is running in process 12345
Task B is running in process 12346
All processes completed

2. 进程池(multiprocessing.Pool

当需要管理大量进程时,使用进程池(Pool)可以更方便地分配和调度任务。

from multiprocessing import Pooldef worker(x):return x * xif __name__ == "__main__":with Pool(4) as pool:  # 创建包含 4 个进程的进程池results = pool.map(worker, range(10))print(results)

输出

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

三、进程间通信

Python 提供了多种方式实现进程间通信,包括队列(Queue)、管道(Pipe)和事件(Event)。

1. 使用 Queue

Queue 提供了线程安全的队列,可以实现进程间的数据共享。

from multiprocessing import Process, Queuedef producer(queue):for i in range(5):queue.put(i)print(f"Produced: {i}")def consumer(queue):while not queue.empty():item = queue.get()print(f"Consumed: {item}")if __name__ == "__main__":q = Queue()p1 = Process(target=producer, args=(q,))p2 = Process(target=consumer, args=(q,))p1.start()p1.join()p2.start()p2.join()

输出

Produced: 0
Produced: 1
Produced: 2
Produced: 3
Produced: 4
Consumed: 0
Consumed: 1
Consumed: 2
Consumed: 3
Consumed: 4

2. 使用 Pipe

Pipe 提供了双向通信的能力。

from multiprocessing import Process, Pipedef sender(pipe):for i in range(5):pipe.send(i)print(f"Sent: {i}")pipe.close()def receiver(pipe):while True:try:item = pipe.recv()print(f"Received: {item}")except EOFError:breakif __name__ == "__main__":parent_conn, child_conn = Pipe()p1 = Process(target=sender, args=(parent_conn,))p2 = Process(target=receiver, args=(child_conn,))p1.start()p2.start()p1.join()p2.join()

输出

Sent: 0
Sent: 1
Sent: 2
Sent: 3
Sent: 4
Received: 0
Received: 1
Received: 2
Received: 3
Received: 4

四、进程同步机制

多进程共享资源时需要同步工具,multiprocessing 提供了 LockEvent 等工具。

1. 使用 Lock

Lock 用于防止多个进程同时访问共享资源。

from multiprocessing import Process, Lockcounter = 0def worker(lock):global counterfor _ in range(100000):with lock:counter += 1if __name__ == "__main__":lock = Lock()p1 = Process(target=worker, args=(lock,))p2 = Process(target=worker, args=(lock,))p1.start()p2.start()p1.join()p2.join()print(f"Final counter value: {counter}")

2. 使用 Event

Event 是一种简单的线程同步原语,用于让一个进程等待另一个进程发出信号。

from multiprocessing import Process, Eventdef worker(event):print("Worker waiting for event to be set...")event.wait()  # 等待事件被设置print("Worker received event signal, starting work!")if __name__ == "__main__":event = Event()p = Process(target=worker, args=(event,))p.start()print("Main process performing some setup...")import timetime.sleep(2)print("Main process setting event.")event.set()  # 触发事件p.join()

输出

Worker waiting for event to be set...
Main process performing some setup...
Main process setting event.
Worker received event signal, starting work!

五、多进程、线程与协程的对比

特性多进程(multiprocessing多线程(threading协程(asyncio
适用场景CPU 密集型任务I/O 密集型任务,简单并发I/O 密集型任务,高性能并发
多核支持可充分利用多核受限于 GIL,无多核支持单线程实现并发,无多核支持
资源隔离每个进程独立,资源隔离性高线程共享内存,隔离性较低协程运行在同一线程,隔离性低
资源开销进程上下文切换开销高线程上下文切换开销较低协程更轻量,占用资源更少
通信方式队列(Queue)、管道(Pipe共享内存或队列事件循环或 asyncio.Queue
编程难度相对复杂较简单语法直观,使用方便

六、总结与推荐

  1. 选择多进程

    • 当任务是 CPU 密集型,需要并行处理时,优先考虑 multiprocessing
    • 适合需要进程隔离的场景,避免共享资源引发的数据竞争。
  2. 选择多线程

    • 适用于 I/O 密集型任务,例如文件操作、网络请求。
    • 如果任务需要共享内存并发处理,多线程更方便。
  3. 选择协程

    • 在高并发的 I/O 密集型任务 中(如异步网络请求),协程是最优选择。
    • 轻量、性能高,适合现代异步编程。

通过合理选择工具,可以在 Python 中充分利用多进程、多线程和协程的优势,打造高性能的并发程序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/66814.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《代码随想录》Day31打卡!

《代码随想录》贪心算法:合并区间 本题的完整题目如下所示: 本题的完整思路如下所示: 1.本题依然是先对数组的左边界进行排序。将数组的第一个元素赋值给current。 2.遍历数组,判断current中的右边界和当前元素的左边界是否有重叠…

windows及linux 安装 Yarn 4.x 版本

1. 确保系统环境准备 a. 安装 Node.js Yarn 依赖于 Node.js,所以需要先安装 Node.js。前往 Node.js 官网 下载并安装适合你的 Windows 版本的 Node.js(推荐 LTS 版本)。安装完成后,打开命令提示符(CMD)或 PowerShell,验证安装:node -v npm -v如果显示版本号,则表示安…

KL 散度:多维度解读概率分布间的隐秘 “距离”

深入理解KL散度:从多维度全面剖析 损失函数相关文章(置顶) 1. KL 散度:多维度解读概率分布间的隐秘 “距离” 2. 熵与交叉熵:从不确定性角度理解 KL 散度 3. 机器学习、深度学习关于熵你所需要知道的一切 引言 KL散即…

Spring bean的生命周期和扩展

bean生命周期流程 生命周期扩展处理说明实例化:createBeanInstance 构造方法, 如Autowired的构造方法注入依赖bean 如UserService构造方法注入AppDAO: Autowired public UserService(AppDAO appDAO) {System.out.println("Autowired appDAO:"…

node-sass@4.14.1报错的最终解决方案分享

输入npm i全安装文件所需的依赖的时候,博主是使用sass去书写的,使用的是node-sass4.14.1和sass-loader7.3.1的版本的,安装的时候老是出现错误, node-sass4.14.1版本不再被支持的原因 node-sass 是一个基于 LibSass 的 Node.js 绑…

设计模式(观察者模式)

设计模式(观察者模式) 第三章 设计模式之观察者模式 观察者模式介绍 观察者模式(Observer Design Pattern) 也被称为发布订阅模式 。模式定义:在对象之间定义一个一对多的依赖,当一个对象状态改变的时候…

将光源视角的深度贴图应用于摄像机视角的渲染

将光源视角的深度贴图应用于摄像机视角的渲染是阴影映射(Shadow Mapping)技术的核心步骤之一。这个过程涉及到将摄像机视角下的片段坐标转换到光源视角下,并使用深度贴图来判断这些片段是否处于阴影中。 1. 生成光源视角的深度贴图 首先&…

PyCharm 的安装与使用(Window)

1 PyCharm 简介 PyCharm 是一款由 JetBrains 公司开发的专门用于 Python 语言开发的集成开发环境(IDE)。以下是其相关介绍: 1.1 特点与功能 智能代码编辑:提供高度智能化的代码编辑器,支持语法高亮、自动补全、代码重…

(vue)el-table-column type=“selection“表格选框怎么根据条件添加禁选

(vue)el-table-column type"selection"表格选框怎么根据条件添加禁选 html <el-table:data"tableData"style"width: 100%"><el-table-columntype"selection"width"55":selectable"checkSelectable">…

Vue3 网络请求

文章目录 Vue3 网络请求CORS问题ajaxfetchaxios Vue3 网络请求 CORS问题 同源&#xff1a;指的是当前用户所在的URL与被请求的URL的协议名、域名、端口必须完全相同。一旦有一个或多个不同&#xff0c;就是非同源请求&#xff0c;也就是我们经常说的跨域请求&#xff0c;简称…

C# 之某度协议登录,JS逆向,手机号绑定,获取CK

.NET兼职社区 .NET兼职社区 .NET兼职社区 .NET兼职社区 有需要指导&#xff0c;请私信我留言V或者去社区找客服。

深入Android架构(从线程到AIDL)_20 IPC的Proxy-Stub设计模式02

2、 IBinder接口的一般用途 前言 一般用途 Android的IPC框架仰赖单一的IBinder接口。此时Client端调用IBinder接口的transact()函数&#xff0c;透过IPC机制而调用到远方(Remote)的onTransact()函数。在Java层框架里&#xff0c; IBinder接口实现于Binder基类&#xff0c;如下…

C++ Json库的使用

1.Json库的使用&#xff0c;包含C Json的创建、读写、字符串Json互转等&#xff0c;覆盖日常使用场景 前提&#xff1a;按照参考的文章部署好nlohmann/json 上代码 #include <iostream> #include <fstream> #include "nlohmann/json.hpp" using json n…

初学stm32 --- ADC单通道采集

目录 ADC寄存器介绍&#xff08;F1&#xff09; ADC控制寄存器 1(ADC_CR1) ADC控制寄存器 2(ADC_CR2) ADC采样时间寄存器1(ADC_SMPR1) ADC采样时间寄存器2(ADC_SMPR2) ADC规则序列寄存器 1(ADC_SQR1) ADC规则序列寄存器 2(ADC_SQR2) ADC规则序列寄存器 3(ADC_SQR3) AD…

FPGA技术的深度理解

目录 引言 FPGA的基本原理 结构组成 工作原理 FPGA的设计流程 设计阶段 编程阶段 实现阶段 FPGA的应用领域 FPGA编程技巧和示例代码 编程技巧 示例代码 结论 引言 FPGA&#xff08;现场可编程门阵列&#xff09;是一种可编程的集成电路&#xff0c;它允许用户根据…

@SneakyThrows 注解详解

SneakyThrows 注解详解 1. 基本介绍 SneakyThrows 是 Lombok 提供的注解&#xff0c;用于简化异常处理&#xff0c;自动生成 try-catch 代码块&#xff0c;将检查型异常转换为非检查型异常。 2. 使用对比 2.1 传统写法 public String readFile(String path) {try {return …

【经典神经网络架构解析篇】【1】LeNet网络详解:模型结构解析、优点、实现代码

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…

qml SpringAnimation详解

1. 概述 SpringAnimation 是 Qt Quick 中用于模拟弹簧效果的动画类。它通过模拟物体在弹簧力作用下的反应&#xff0c;产生一种振荡的动画效果&#xff0c;常用于模拟具有自然回弹、弹性和振动的动态行为。这种动画效果在 UI 中广泛应用&#xff0c;特别是在拖动、拉伸、回弹等…

day03-前端Web-Vue3.0基础

目录 前言1. Vue概述2. 快速入门2.1 需求2.2 步骤2.3 实现 3. Vue指令3.1 介绍3.2 v-for3.2.1 介绍3.2.2 演示3.2.3 v-for的key3.2.4 案例-列表渲染 3.3 v-bind3.3.1 介绍3.3.2 演示3.3.3 案例-图片展示 3.4 v-if & v-show3.4.1 介绍3.4.2 案例-性别职位展示 3.6 v-model3.…

Jenkins pipeline 发送邮件及包含附件

Jenkins pipeline 发送邮件及包含附件 设置邮箱开启SMTP服务 此处适用163 邮箱 开启POP3/SMTP服务通过短信获取TOKEN &#xff08;保存TOKEN, 后面Jenkins会用到&#xff09; Jenkins 邮箱设置 安装 Build Timestamp插件 设置全局凭证 Dashboard -> Manage Jenkins …