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

news2025/1/12 3:06:59

在 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 os

def 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 Pool

def worker(x):
    return x * x

if __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, Queue

def 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, Pipe

def 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:
            break

if __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, Lock

counter = 0

def worker(lock):
    global counter
    for _ in range(100000):
        with lock:
            counter += 1

if __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, Event

def 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 time
    time.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.coloradmin.cn/o/2275269.html

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

相关文章

DC/AC并网逆变器模型与仿真MATLAB

DC/AC并网逆变器是一种将直流电(DC)转化为交流电(AC),并将其与电网并联的设备。它的核心功能是实现直流电源(如光伏电池板或储能电池)与电网的有效连接,同时保证输出电能质量满足电网…

Flink三种集群部署模型

这里写自定义目录标题 Flink 集群剖析Flink 应用程序执行Flink Session 集群(Session Mode)Flink Job 集群(以前称为per-job)Flink Application 集群(Application Mode) 参考 Flink 集群剖析 Flink 运行时…

JVM实战—12.OOM的定位和解决

大纲 1.如何对系统的OOM异常进行监控和报警 2.如何在JVM内存溢出时自动dump内存快照 3.Metaspace区域内存溢出时应如何解决(OutOfMemoryError: Metaspace) 4.JVM栈内存溢出时应如何解决(StackOverflowError) 5.JVM堆内存溢出时应该如何解决(OutOfMemoryError: Java heap s…

一文读懂「LoRA」:大型语言模型的低秩适应

LoRA: Low-Rank Adaptation of Large Language Models 前言 LoRA作为大模型的微调框架十分实用,在LoRA出现以前本人都是通过手动修改参数、优化器或者层数来“炼丹”的,具有极大的盲目性,但是LoRA技术能够快速微调参数,如果LoRA…

IT面试求职系列主题-人工智能(一)

想成功求职,必要的IT技能一样不能少,再从人工智能基础知识来一波吧。 1)您对人工智能的理解是什么? 人工智能是计算机科学技术,强调创造能够模仿人类行为的智能机器。这里智能机器可以定义为能够像人一样行动、像人一…

浏览器报错:您的连接不是私密连接,Kubernetes Dashboard无法打开

问题描述 部署完成Kubernetes Dashboard后,打开HTTPS的web页面,Chrome和Edge浏览器都无法正常加载页面,会提示您的连接不是私密连接的报错。 ​​​​​​​​​​​​ 原因: 浏览器不信任这些自签名的ssl证书,为了…

【Unity插件】解决移动端UI安全区问题 - Safe Area Helper

在移动端设计界面时,必须要考虑的就是UI的安全区。 Unity本身也提供了Safearea的API。 但在asset store时已经有人提供了免费的插件(Safe Area Helper),我们可以直接使用。 插件链接: https://assetstore.unity.com/p…

ffmpeg7.0 aac转pcm

#pragma once #define __STDC_CONSTANT_MACROS #define _CRT_SECURE_NO_WARNINGSextern "C" { #include "libavcodec/avcodec.h" }//缓冲区大小(缓存5帧数据) #define AUDIO_INBUF_SIZE 40960 /*name depthu8 8s16 …

USRP X310 Windows 烧录镜像

说明 USRP-X 系列设备包含两个用于两个以太网通道的 SFP 端口。由于 SFP 端口支持 1 千兆 (SFP) 和 10 千兆 (SFP) 收发器,因此 UHD 附带了多个 FPGA 图像,以确定上述接口的行为。 注意:Aurora 图像需要从 FPGA 源代码手动构建。 FPGA 图像…

新型物联网智能断路器功能参数介绍

安科瑞刘鸿鹏 摘要 智能断路器作为现代配电系统的重要组成部分,以其实时监测、多重保护和远程操控的智能化功能,显著提升了电力系统的运行效率和安全性。本文以ASCB1系列智能断路器为例,探讨其技术特点和在工业、商业及民用建筑中的应用价…

119.使用AI Agent解决问题:Jenkins build Pipeline时,提示npm ERR! errno FETCH_ERROR

目录 1.Jenkins Build时的错误 2.百度文心快码AI智能体帮我解决 提问1:jenkins中如何配置npm的源 提问2:jenkins pipeline 类型为pipeline script from SCM时,如何配置npm源 3.最终解决方法-Jenkinsfile的修改 4.感触 1.Jenkins Build时…

pytest+allure 入门

使用allure如何生成自动化测试报​​​​​​告 ?一文详解allure的使用 。_allure测试报告-CSDN博客 例子: import allure import pytest import osallure.epic("闹钟") allure.feature("闹钟增删") class TestSchedule():def setu…

【FPGA】时序约束与分析

设计约束 设计约束所处环节: 约束输入 分析实现结果 设计优化 设计约束分类: 物理约束:I/O接口约束(例如引脚分配、电平标准设定等物理属性的约束)、布局约束、布线约束以及配置约束 时序约束:设计FP…

【Vim Masterclass 笔记09】S06L22:Vim 核心操作训练之 —— 文本的搜索、查找与替换操作(第一部分)

文章目录 S06L22 Search, Find, and Replace - Part One1 从光标位置起,正向定位到当前行的首个字符 b2 从光标位置起,反向查找某个字符3 重复上一次字符查找操作4 定位到目标字符的前一个字符5 单字符查找与 Vim 命令的组合6 跨行查找某字符串7 Vim 的增…

win32汇编环境,窗口程序中对按钮控件常用操作的示例

;运行效果 ;win32汇编环境,窗口程序中对按钮控件常用操作的示例 ;常用的操作,例如创建按钮控件,使其无效,改变文本,得到文本等。 ;将代码复制进radasm软件里,直接就可以编译运行。重点部分加备注。 ;>&g…

继承(7)

大家好,今天我们继续来学习一下继承的知识,这方面需要大家勤动脑才能理解,那么我们来看。 1.9 protected关键字 在类和对象章节中,为了实现封装特性,java中引入访向限定符,主要限定:类或者类中成员能否在类外和其他包中被访问. …

基于RK3568/RK3588大车360度环视影像主动安全行车辅助系统解决方案,支持ADAS/DMS

产品设计初衷 HS-P2-2D是一款针对大车盲区开发的360度全景影像 安全行车辅助系统,通过车身四周安装的超广角像机,经算法合成全景鸟瞰图,通过鸟瞰图,司机非常清楚的看清楚车辆四周情况,大大降低盲区引发的交通事故。 产…

NVIDIA发布GeForce RTX 50 系列,售价549美元起

2025 CES消费电子展(1月7日至10日,美国拉斯维加斯)正式开幕。北京时间1月7日 (星期二)上午10:30,NVIDIA举办主题演讲,CEO黄仁勋担任主讲。正式发布了全新的RTX 50系列显卡!一月下旬上市。同时公布了各版本的…

后端:Spring(IOC、AOP)

文章目录 1. Spring2. IOC 控制反转2-1. 通过配置文件定义Bean2-1-1. 通过set方法来注入Bean2-1-2. 通过构造方法来注入Bean2-1-3. 自动装配2-1-4. 集合注入2-1-5. 数据源对象管理(第三方Bean)2-1-6. 在xml配置文件中加载properties文件的数据(context命名空间)2-1-7. 加载容器…

基于EasyExcel实现通用版一对一、一对多、多层嵌套结构数据导出并支持自动合并单元格

接口功能 通用 支持一对一数据结构导出 支持一对多数据结构导出 支持多层嵌套数据结构导出 支持单元格自动合并 原文来自:https://blog.csdn.net/qq_40980205/article/details/136564176 新增及修复 基于我自己的使用场景,新增并能修复一下功能&#x…