当前位置: 首页 > news >正文

深入理解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]

相关文章:

深入理解Python多进程编程 multiprocessing

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

jQuery AJAX 方法详解

jQuery AJAX 方法详解 引言 随着互联网技术的不断发展,前端开发领域的技术也在不断更新迭代。jQuery 作为一种广泛使用的前端JavaScript库,极大地简化了DOM操作和事件处理。在众多jQuery功能中,AJAX(Asynchronous JavaScript and XML)方法尤为突出,它允许我们在不重新加…...

青少年编程都有哪些比赛可以参加

Python小学生可参加的赛事: 电子学会青少年编程考级、中国计算机学会编程能力等级认证、蓝桥杯、 信奥赛CSP-J/S初赛/NOIP(推荐C)、编程设计、信息素养、科技创新赛; 升学助力(科技特长生、大学)、企业、出国留学; python比赛&am…...

sql server 数据库 锁教程及锁操作

SQL Server数据库 锁的教程 SQL Server 的数据库锁是为了保证数据库的并发性和数据一致性而设计的。锁机制能够确保多个事务不会同时修改同一数据,从而避免数据冲突和不一致的发生。理解 SQL Server 的锁机制对于开发高效、并发性强的数据库应用非常重要。 1. 锁的…...

存储结构 分类

存储结构 1,顺序存储结构 用一组地址连续的存储单元依次存储线性表的各个数据元素, 适用于频繁查询时使用。 2,链式存储结构 在计算机中用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的),适用于在较…...

VSCode 中 Git 添加了多个远端,如何设置默认远端

VSCode 中 Git 添加了多个远端,如何设置默认远端 查看分支:设置默认远端手动指定远端 查看分支: * 表示当前默认远端 git branch -vv* master a1b2c3d [origin/main] Fix typo dev d4e5f6g [upstream/dev] Add feature设置默认远端 将本…...

项目中一些不理解的问题

1.Mybatis是干啥的 他是用来帮我们操作数据库的,相当于是我们的一个助手: 我们想要得到数据库中的什么数据,就可以告诉mybatis,他会给我们想要的结果,同时,我们想要对数据库做出什么操作,也可…...

vue3 + thinkphp 接入 七牛云 DeepSeek-R1/V3 流式调用和非流式调用

示例 如何获取七牛云 Token API 密钥 https://eastern-squash-d44.notion.site/Token-API-1932c3f43aee80fa8bfafeb25f1163d8 后端 // 七牛云 DeepSeek API 地址private $deepseekUrl https://api.qnaigc.com/v1/chat/completions;private $deepseekKey 秘钥;// 流式调用pub…...

Linux应用之构建命令行解释器(bash进程)

目录 1.分析 2.打印输入提示符 3.读取并且处理输入字符串 4.创建子进程并切换 5.bash内部指令 6.完整代码 1.分析 当我们登录服务器的时候,命令行解释器就会自动加载出来。接下来我们就。在命令行中输入指令来达到我们想要的目的。 我们在命令行上输入的…...

php 系统命令执行及绕过

文章目录 php的基础概念php的基础语法1. PHP 基本语法结构2. PHP 变量3.输出数据4.数组5.超全局变量6.文件操作 php的命令执行可以执行命令的函数命令执行绕过利用代码中命令(如ls)执行命令替换过滤过滤特定字符串神技:利用base64编码解码的绕…...

保护大数据的最佳实践方案

在当今数字化时代,保障大数据安全的重要性再怎么强调也不为过。 随着科技的迅猛发展以及对数据驱动决策的依赖日益加深,企业必须将保护其宝贵信息置于首位。 我们将深入探讨保障大数据安全的流程,并讨论关键原则、策略、工具及技术&#xf…...

在高流量下保持WordPress网站的稳定和高效运行

随着流量的不断增加,网站的稳定和高效运行变得越来越重要,特别是使用WordPress搭建的网站。流量过高时,网站加载可能会变慢,甚至崩溃,直接影响用户体验和网站正常运营。因此,我们需要采取一些有效的措施&am…...

Redis7——基础篇(二)

前言:此篇文章系本人学习过程中记录下来的笔记,里面难免会有不少欠缺的地方,诚心期待大家多多给予指教。 基础篇: Redis(一) 接上期内容:上期完成了Redis环境的搭建。下面开始学习Redis常用命令…...

Docker 容器安装 Dify的两种方法

若 Windows 已安装 Docker,可借助 Docker 容器来安装 Dify: 一、方法一 1. 拉取 Dify 镜像 打开 PowerShell 或命令提示符(CMD),运行以下命令从 Docker Hub 拉取 Dify 的镜像(Docker Hub中找到该命令行&…...

golang常用库之-swaggo/swag根据注释生成接口文档

文章目录 golang常用库之-swaggo/swag库根据注释生成接口文档什么是swaggo/swag golang常用库之-swaggo/swag库根据注释生成接口文档 什么是swaggo/swag github:https://github.com/swaggo/swag 参考文档:https://golang.halfiisland.com/community/pk…...

docker中pull hello-world的时候出现报错

Windows下的docker中pull的时候出现下面的错误: PS C:\Users\xxx> docker pull hello-world Using default tag: latest Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connect…...

NPM环境搭建指南

NPM(Node Package Manager)是 Node.js 的包管理工具,堪称前端开发的基石。本文将手把手教你 在Mac、Windows、Linux三大系统上快速搭建NPM环境,并验证是否成功。 一、Mac系统安装NPM 方法1:通过Homebrew安装&#xff…...

【CSS进阶】常见的页面自适应的方法

在前端开发中,自适应布局(Responsive Design)是一种让网页能够适应不同屏幕尺寸、设备和分辨率的技术。常见的自适应布局方法包括 流式布局、弹性布局(Flexbox)、栅格布局(Grid)、媒体查询&…...

Linux系统配置阿里云yum源,安装docker

配置阿里云yum源 需要保证能够访问阿里云网站 可以先ping一下看看(阿里云可能禁ping,只要能够解析为正常的ip地址即可) ping mirrors.aliyun.com脚本 #!/bin/bash mkdir /etc/yum.repos.d/bak mv /etc/yum.repos.d/*.repo /etc/yum.repos…...

啥是CTF?新手如何入门CTF?网络安全零基础入门到精通实战教程!

CTF是啥 CTF 是 Capture The Flag 的简称,中文咱们叫夺旗赛,其本意是西方的一种传统运动。在比赛上两军会互相争夺旗帜,当有一方的旗帜已被敌军夺取,就代表了那一方的战败。在信息安全领域的 CTF 是说,通过各种攻击手…...

业务系统对接大模型的基础方案:架构设计与关键步骤

业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...

visual studio 2022更改主题为深色

visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

EtherNet/IP转DeviceNet协议网关详解

一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...

鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/

使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案

JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停​​ 1. ​​安全点(Safepoint)阻塞​​ ​​现象​​:JVM暂停但无GC日志,日志显示No GCs detected。​​原因​​:JVM等待所有线程进入安全点(如…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题

分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...