深入理解Python多进程编程 multiprocessing

深入理解Python多进程编程 multiprocessing

flyfish

Python 的 multiprocessing 模块允许创建多个进程,从而可以利用多核处理器的能力来并行执行任务。这意味着程序的不同部分可以在不同的CPU核心上同时运行,极大地提高了处理效率,特别是在执行计算密集型任务时。

与多线程相比,multiprocessing 使用的是系统级的进程而不是线程。每个进程都有独立的内存空间和系统资源,而线程则共享同一个进程的内存空间。因此,在Python中(特别是由于全局解释器锁GIL的存在),对于CPU密集型任务,使用multiprocessing比多线程能更有效地利用多核CPU的优势。

进程的概念

在计算机操作系统中,进程是操作系统进行资源分配和调度的基本单位。一个进程可以包含多个线程。当使用multiprocessing模块时,可以创建新的进程,这些新进程将与主程序并行运行,并且它们各自拥有独立的内存空间。

示例代码1:单个进程打印数字

下面是一个简单的示例,演示如何使用multiprocessing模块创建一个进程来打印从1到5的数字:

import multiprocessing
import timedef print_numbers():"""打印从1到5的数字"""for i in range(1, 6):print("数字:", i)time.sleep(1)  # 模拟耗时操作if __name__ == "__main__":# 创建一个新的进程process = multiprocessing.Process(target=print_numbers)# 启动进程process.start()# 等待进程完成process.join()
数字: 1
数字: 2
数字: 3
数字: 4
数字: 5
  • multiprocessing.Process():创建一个新的进程对象。
  • target=print_numbers:指定该进程的目标函数为print_numbers
  • process.start():启动进程。
  • process.join():等待进程结束。

示例代码2:两个进程分别打印不同字符串

下面是另一个示例,演示如何同时启动两个进程,每个进程打印不同的字符串:

import multiprocessingdef print_message(message):"""打印传入的消息"""print(f"消息: {message}")if __name__ == "__main__":# 创建两个进程process1 = multiprocessing.Process(target=print_message, args=("Hello from Process 1",))process2 = multiprocessing.Process(target=print_message, args=("Hello from Process 2",))# 启动两个进程process1.start()process2.start()# 等待两个进程都完成process1.join()process2.join()
消息: Hello from Process 1
消息: Hello from Process 2

在这个例子中,定义了一个print_message函数,它接受一个字符串参数并打印出来。然后,创建了两个进程,每个进程都调用这个函数,但传递了不同的字符串参数。通过args参数,可以向目标函数传递额外的参数。最后,启动这两个进程,并等待它们完成各自的执行。这样,就可以看到两个进程几乎同时开始工作,并打印出各自的消息。

示例3:使用 multiprocessing.Value 在多个进程中共享一个计数器

multiprocessing.Value
Value 允许多个进程共享一个值。它适用于需要在多个进程中共享简单数据类型(如整数或浮点数)的情况。

import multiprocessingdef increment(counter, lock):"""增加计数器的值"""for _ in range(1000):with lock:counter.value += 1if __name__ == "__main__":# 创建一个共享的整数值和锁counter = multiprocessing.Value('i', 0)  # 'i' 表示整数类型lock = multiprocessing.Lock()# 创建多个进程来增加计数器processes = [multiprocessing.Process(target=increment, args=(counter, lock)) for _ in range(10)]# 启动所有进程for p in processes:p.start()# 等待所有进程完成for p in processes:p.join()print("最终计数器值:", counter.value)
最终计数器值: 10000
  • multiprocessing.Value(typecode_or_type, *args, lock=True):创建一个新的共享值对象。typecode_or_type 指定了要共享的数据类型(例如 'i' 表示整数)。
  • value.value:访问共享值的实际内容。
  • lock:确保对共享资源的安全访问,防止竞态条件。

进程(Process)和线程(Thread)在Python中的区别

特性进程(Process)线程(Thread)
内存空间每个进程有独立的内存空间所有线程共享同一进程的内存空间
资源消耗开销较大,需要更多系统资源轻量级,开销小,资源共享
通信难度进程间通信复杂(IPC),如管道、套接字等线程间通信简单,直接访问相同变量和数据结构
全局解释器锁(GIL)不受GIL限制,适合计算密集型任务受GIL限制,对于计算密集型任务效率提升有限
适用场景计算密集型任务,稳定性要求高的应用I/O密集型任务,快速响应用户界面的应用
崩溃影响一个进程崩溃不影响其他进程一个线程出错可能导致整个进程崩溃

Python中多线程(Thread)和多进程(Process)的区别

特性多线程(Thread)多进程(Process)
内存空间所有线程共享同一进程的内存空间每个进程有独立的内存空间
资源消耗轻量级,开销小,资源共享开销较大,需要更多系统资源
通信难度线程间通信简单,直接访问相同变量和数据结构进程间通信复杂(IPC),如管道、套接字等
全局解释器锁 (GIL)受GIL限制,对于计算密集型任务效率提升有限不受GIL限制,适合计算密集型任务
适用场景I/O密集型任务,快速响应用户界面的应用计算密集型任务,稳定性要求高的应用
崩溃影响一个线程出错可能导致整个进程崩溃一个进程崩溃不影响其他进程
创建与销毁开销创建和销毁开销较小创建和销毁开销较大
并发性能对于I/O密集型任务性能较好,但对于CPU密集型任务受限对于CPU密集型任务性能较好
示例用途网络请求、文件读写、GUI应用等数据分析、图像处理、科学计算等

进程间通信

在Python的multiprocessing模块中,提供了几种常用的进程间通信(IPC)方式,包括队列(Queue)、管道(Pipe)等。这些工具允许不同的进程之间安全地传递数据。

使用 multiprocessing.Queue 实现进程间通信

Queue 是一个线程和进程安全的 FIFO 队列,非常适合用于进程间的简单数据交换。

示例代码:

import multiprocessingdef producer(queue):"""生产者函数,向队列中添加数据"""for i in range(5):queue.put(f"数据 {i}")print(f"生产者放入: 数据 {i}")def consumer(queue):"""消费者函数,从队列中取出数据"""while not queue.empty():data = queue.get()print(f"消费者获取: {data}")if __name__ == "__main__":# 创建一个队列对象queue = multiprocessing.Queue()# 创建生产者和消费者进程p1 = multiprocessing.Process(target=producer, args=(queue,))p2 = multiprocessing.Process(target=consumer, args=(queue,))# 启动进程p1.start()p2.start()# 等待两个进程完成p1.join()p2.join()
生产者放入: 数据 0
生产者放入: 数据 1
生产者放入: 数据 2
生产者放入: 数据 3
生产者放入: 数据 4
消费者获取: 数据 0
消费者获取: 数据 1
消费者获取: 数据 2
消费者获取: 数据 3
消费者获取: 数据 4
  • 队列的使用queue.put() 用于向队列中添加数据,queue.get() 用于从队列中取出数据。
  • 数据传递原理:生产者进程通过调用 put 方法将数据放入队列,而消费者进程通过调用 get 方法从队列中取出数据。Queue 对象是进程安全的,因此多个进程可以同时访问它而不发生冲突。
使用 multiprocessing.Pipe 实现进程间通信

Pipe 提供了一个双向通道,适用于两个进程之间的直接通信。

示例代码:

import multiprocessingdef sender(conn, messages):"""发送者函数,通过管道发送消息"""for msg in messages:conn.send(msg)print(f"发送者发送: {msg}")conn.close()def receiver(conn):"""接收者函数,通过管道接收消息"""while True:msg = conn.recv()if msg == "END":breakprint(f"接收者接收: {msg}")if __name__ == "__main__":# 创建一个管道对象parent_conn, child_conn = multiprocessing.Pipe()# 准备要发送的消息messages = ["Hello", "from", "sender", "END"]# 创建发送者和接收者进程p1 = multiprocessing.Process(target=sender, args=(child_conn, messages))p2 = multiprocessing.Process(target=receiver, args=(parent_conn,))# 启动进程p1.start()p2.start()# 等待两个进程完成p1.join()p2.join()
发送者发送: Hello
发送者发送: from
发送者发送: sender
发送者发送: END
接收者接收: Hello
接收者接收: from
接收者接收: sender

进程池的使用

multiprocessing.Pool 是一个用于管理一组工作进程的类,它可以简化并行任务的分配和结果收集。

示例代码:使用 Pool 并行计算数字的平方
import multiprocessingdef square(n):"""计算一个数的平方"""return n * nif __name__ == "__main__":# 定义要处理的数字列表numbers = [1, 2, 3, 4, 5]# 创建一个包含4个进程的进程池with multiprocessing.Pool(processes=4) as pool:# 使用map方法将square函数应用于每个数字results = pool.map(square, numbers)print("结果:", results)
结果: [1, 4, 9, 16, 25]
  • 进程池的概念和作用Pool 允许你指定一定数量的工作进程,并且可以通过 mapapply 等方法轻松地将任务分配给这些进程。这样可以有效地利用多核CPU来加速计算密集型任务。
  • 设置进程池大小:通过 processes 参数指定进程池中的工作进程数量,默认情况下,它会根据系统CPU核心数自动调整。
  • 处理任务的方式pool.map() 方法类似于内置的 map() 函数,但它会在多个进程中并行执行。在这个例子中,我们将 square 函数应用到 numbers 列表中的每个元素,并返回计算结果。

Semaphore(信号量)

信号量是一种更高级的同步机制,可以用来控制同时访问某一资源的进程数量。

示例:使用 Semaphore 控制并发访问

import multiprocessing
import timedef worker(semaphore, name):with semaphore:print(f"{name} 获得信号量")time.sleep(1)if __name__ == "__main__":semaphore = multiprocessing.Semaphore(3)  # 最多允许3个进程同时访问processes = [multiprocessing.Process(target=worker, args=(semaphore, f"进程 {i}")) for i in range(6)]for p in processes:p.start()for p in processes:p.join()

Event(事件)

事件是一种简单的线程间通信机制,可以让一个或多个进程等待某个特定事件的发生。

示例:使用 Event 实现进程间的同步

import multiprocessing
import timedef wait_for_event(event):print("等待事件触发...")event.wait()  # 阻塞直到事件被设置print("事件已触发!")def set_event(event):time.sleep(3)event.set()  # 触发事件if __name__ == "__main__":event = multiprocessing.Event()p1 = multiprocessing.Process(target=wait_for_event, args=(event,))p2 = multiprocessing.Process(target=set_event, args=(event,))p1.start()p2.start()p1.join()p2.join()

Manager(管理器)

Manager 提供了更高层次的接口,可以创建可以在不同进程之间共享的数据结构,如列表、字典等。

示例:使用 Manager 创建共享数据结构

import multiprocessingdef append_to_list(shared_list, item):shared_list.append(item)print(f"添加到共享列表: {item}")if __name__ == "__main__":with multiprocessing.Manager() as manager:shared_list = manager.list()  # 创建一个可共享的列表processes = [multiprocessing.Process(target=append_to_list, args=(shared_list, i)) for i in range(5)]for p in processes:p.start()for p in processes:p.join()print("最终共享列表:", list(shared_list))

文中processes = [multiprocessing.Process(target=append_to_list, args=(shared_list, i)) for i in range(5)]这一句 等于下面的代码

processes = []
for i in range(5):p = multiprocessing.Process(target=append_to_list, args=(shared_list, i))processes.append(p)

共享内存

multiprocessing 还支持通过共享内存的方式在进程之间共享数据,这对于大规模数据共享特别有用。

示例:使用 Array 共享数组

import multiprocessingdef modify_array(shared_array, index, value):shared_array[index] = valueif __name__ == "__main__":array = multiprocessing.Array('i', [1, 2, 3, 4, 5])  # 创建共享数组processes = [multiprocessing.Process(target=modify_array, args=(array, i, i*10)) for i in range(len(array))]for p in processes:p.start()for p in processes:p.join()print("修改后的数组:", list(array))
修改后的数组: [0, 10, 20, 30, 40]

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

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

相关文章

阿里云上的网站配置HTTPS

1. 获取SSL证书 创建证书 下载证书 下载 上传 .key .pem 文件 到 阿里云服务器 /etc/nginx/ssl nginx.conf 配置 server { listen 443 ssl; server_name yuming; ssl_certificate /etc/nginx/ssl/*.pem; ssl_certificate_key /etc/nginx/ssl/*.key;

jetbrains IDEA集成大语言模型

一、CodeGPT ‌CodeGPT‌是由CSDN打造的一款生成式AI产品,专为开发者量身定制。它能够提供强大的技术支持,帮助开发者在学习新技术或解决实际工作中的各种计算机和开发难题‌1。 idea集成 1.在线安装:直接在线安装 2.离线安装 JetBrains Mar…

记录一次部署PC端网址全过程

当我查看我之前写的文章时、顿时惊奇发出感慨:啥时候写的?是我写的么?疑惑重重… 所以说,好记性不如烂笔头。 记录一次部署PC端网址全过程 部署PC端网址分是三步:第一步:申请域名并映射到外网IP &#xff0…

鸿蒙5.0实战案例:关于图像撕裂、掉帧等异常现象的原理以及优化方案

往期推文全新看点(文中附带全新鸿蒙5.0全栈学习笔录) ✏️ 鸿蒙(HarmonyOS)北向开发知识点记录~ ✏️ 鸿蒙(OpenHarmony)南向开发保姆级知识点汇总~ ✏️ 鸿蒙应用开发与鸿蒙系统开发哪个更有前景&#…

C#项目05-猜数字多线程

本项目利用多线程,通过点击按钮猜数字, 知识点 线程 基本概念 进程:一组资源,构成一个正在运行的程序,这些资源包括地址空间、文件句柄以及程序启动需要的其他东西的载体。 线程:体现一个程序的真实执行情况, 线…

广西壮族自治区园区投促中心党委书记陶德文率团到访深兰科技

2月16日,广西壮族自治区园区投促中心党委书记、主任,自治区园区办党组成员陶德文率团来到深兰科技集团上海总部考察调研,并与深兰科技集团创始人、董事长陈海波等集团管理层座谈交流,双方围绕深兰科技人工智能项目落地广西的相关事…

推荐几款较好的开源成熟框架

一. 若依: 1. 官方网站:https://doc.ruoyi.vip/ruoyi/ 2. 若依SpringBootVueElement 的后台管理系统:https://gitee.com/y_project/RuoYi-Vue 3. 若依SpringBootVueElement 的后台管理系统:https://gitee.com/y_project/RuoYi-Cl…

【Bert】自然语言(Language Model)入门之---Bert

every blog every motto: Although the world is full of suffering, it is full also of the overcoming of it 0. 前言 对bert进行梳理 论文: BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding 时间:…

基于MATLAB的均匀面阵MUSIC算法DOA估计仿真

基于MATLAB的均匀面阵MUSIC算法DOA估计仿真 文章目录 前言一、二维MUSIC算法原理二、二维MUSIC算法MATLAB仿真三、MATLAB源代码总结 前言 \;\;\;\;\; 在波达角估计算法中,MUSIC 算法与ESPRIT算法属于特征结构子空间算法,是波达角估计算法中的基石。在前面…

Linux 命令

含义: Linux号称万物皆文件 cd 切换目录 .. 当前目录的上一级目录 ~波浪线,当前用户的home目录,比如root用户home目录是/root cd .. :进入上一级目录 pwd:查看当前位置 查看命令 ls:列出目录内容,包括参数-l&…

一周学会Flask3 Python Web开发-Debug模式开启

锋哥原创的Flask3 Python Web开发 Flask3视频教程: 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 默认情况,项目开发是普通模式,也就是你修改了代码,必须重启项目,新代码才生效&…

在VS-qt的程序中,后期增加PCH预编译功能,提高编译速度

由于前期创建qt程序的时候未勾选pch功能,导致没有启动预编译的功能. 这种情况下需要增加pch功能应该怎么做? 在项目中增加2个文件 stdafx.h和stdafx.cpp文件 stdafx.h增加qt常用头文件 #pragma once //windows #include <windows.h>//qt常用 #include <QObject&g…

天翼云910B部署DeepSeek蒸馏70B LLaMA模型实践总结

一、项目背景与目标 本文记录在天翼云昇腾910B服务器上部署DeepSeek 70B模型的全过程。该模型是基于LLaMA架构的知识蒸馏版本&#xff0c;模型大小约132GB。 1.1 硬件环境 - 服务器配置&#xff1a;天翼云910B服务器 - NPU&#xff1a;8昇腾910B (每卡64GB显存) - 系统内存&…

Python 语法及入门 (超全超详细) 专为Python零基础 一篇博客让你完全掌握Python语法

前言&#xff1a; 本篇博客超级详细&#xff0c;请尽量使用电脑端结合目录阅读 阅读时请打开右侧 “只看目录” 方便阅读 一、什么是Python 1.1 Python的诞生 1989年&#xff0c;为了打发圣诞节假期&#xff0c;Gudio van Rossum吉多 范罗苏姆&#xff08;龟叔&#xff09;决…

【架构】分层架构 (Layered Architecture)

一、分层模型基础理论 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/0365cf0bfa754229bdedca6b472bffc7.png 1. 核心定义 分层架构(Layered Architecture)模型是一种常见的软件设计架构,它将软件系统按照功能划分为不同的层次,每个层次都有特定的职责和功能…

2024年国赛高教杯数学建模C题农作物的种植策略解题全过程文档及程序

2024年国赛高教杯数学建模 C题 农作物的种植策略 原题再现 根据乡村的实际情况&#xff0c;充分利用有限的耕地资源&#xff0c;因地制宜&#xff0c;发展有机种植产业&#xff0c;对乡村经济的可持续发展具有重要的现实意义。选择适宜的农作物&#xff0c;优化种植策略&…

捷米特 JM - RTU - TCP 网关应用 F - net 协议转 Modbus TCP 实现电脑控制流量计

一、项目背景 在某工业生产园区的供水系统中&#xff0c;为了精确监测和控制各个生产环节的用水流量&#xff0c;需要对分布在不同区域的多个流量计进行集中管理。这些流量计原本采用 F - net 协议进行数据传输&#xff0c;但园区的监控系统基于 Modbus TCP 协议进行数据交互&…

遥感影像目标检测:从CNN(Faster-RCNN)到Transformer(DETR)

我国高分辨率对地观测系统重大专项已全面启动&#xff0c;高空间、高光谱、高时间分辨率和宽地面覆盖于一体的全球天空地一体化立体对地观测网逐步形成&#xff0c;将成为保障国家安全的基础性和战略性资源。未来10年全球每天获取的观测数据将超过10PB&#xff0c;遥感大数据时…

iOS事件传递和响应

背景 对于身处中小公司且业务不怎么复杂的程序员来说&#xff0c;很多技术不常用&#xff0c;你可能看过很多遍也都大致了解&#xff0c;但是实际让你讲&#xff0c;不一定讲的清楚。你可能说&#xff0c;我以独当一面&#xff0c;应对自如了&#xff0c;但是技术的知识甚多&a…

【核心算法篇十三】《DeepSeek自监督学习:图像补全预训练方案》

引言:为什么自监督学习成为AI新宠? 在传统监督学习需要海量标注数据的困境下,自监督学习(Self-Supervised Learning)凭借无需人工标注的特性异军突起。想象一下,如果AI能像人类一样通过观察世界自我学习——这正是DeepSeek图像补全方案的技术哲学。根据,自监督学习通过…