进程与进程间通信(IPC)

news/2025/10/28 21:58:33/文章来源:https://www.cnblogs.com/xi-yongqi/p/19172819

进程

  • 在 Python 中,进程(Process) 是操作系统进行资源分配和调度的基本单位,指一个正在运行的 Python 程序实例。每个进程拥有独立的内存空间、文件描述符、全局变量等资源,进程之间相互隔离(默认无法直接共享数据),需通过特定机制(IPC)实现通信。

为什么 Python 需要多进程?

  • Python 由于存在GIL(全局解释器锁)的限制:在同一时刻,一个 Python 解释器只能执行一个线程的字节码。这导致多线程在CPU 密集型任务(如大规模计算)中无法真正利用多核 CPU(多线程会因 GIL 切换产生额外开销,效率甚至低于单线程)。
  • 而多进程可以绕过 GIL:每个进程拥有独立的 Python 解释器和 GIL,多个进程可同时在不同 CPU 核心上运行,从而真正实现并行计算,提升 CPU 密集型任务的效率。
  • Python 中创建进程的核心工具:multiprocessing 模块

僵尸进程和孤儿进程

前言
  1. 在unix / Linux 系统中 正常情况下 所有的子进程都是由父进程创建的,子进程再创建自己的子进程
  2. 子进程的结束和父进程的运行是一个异步的过程,也就是说当一个进程运行结束时,它的父进程并不知道,这时候就需要由一个进程来帮助我们完成他工作终止后的收尾工作 , 父进程需要调用 wait 和 waitpid 两个进程来获取到子进程的终止状态
  3. 子进程死亡的时候万一父进程没有反应过来或者是出现了其他问题,就会导致子进程没人管
僵尸进程
  • 僵尸进程就是指子进程死亡之后,父进程没有管他,其它的人也没人管它,就会导致这个子进程的资源没有得到正确的释放从而导致占用资源
  • 他会存在于当前的进程列表中并且占用资源,影响到系统的运行
孤儿进程
  • 父进程在子进程结束之前就已经结束了,导致子进程与父进程之间的通信消失,这时子进程就会变成一个孤儿进程
  • 但是这种孤儿进程会有福利院 (init进程)接管,由当前的 init 进程负责释放当前的资源
孤儿进程和僵尸进程的危害性
  • 僵尸进程危害性更大,不会主动关闭子进程 子进程还会占用系统资源
僵尸进程的解决办法
  1. 自己主动杀死父进程/子进程
  2. 开启多进程的时候记得join, join会主动回收掉僵尸进程
  3. 建立一个信号(可以看我的另一篇文章,里面有关于信号的解释)
  4. 当子进程结束之后向主进程反馈信号,一旦主进程获取到当前的信号就会去主动杀死当前子进程

守护进程

  • 守护进程 (daemon) 是在计算机系统启动时就已经运行,并且一直在后台运行的一类特殊进程。
  • 它们通常不与用户直接交互,也不接受标准输入和输出,而是在后台执行某种任务或提供某种服务。
  • 守护进程往往是由系统管理员手动启动的,它们可以在系统启动时自动启动,一直运行在后台,直到系统关闭或被停止。
  • 常见的守护进程包括网络服务 (如 web 服务器、邮件服务器、 ftp服务器等)、日志记录系统 (如系统日志服务、应用程序日志服务等) 等。
  • 守护进程通常在后台运行,不需要用户交互,并且有较高的权限,因此编写守护进程需要特别注意安全性和稳定性。
import multiprocessing
import timedef daemon_task():"""守护进程任务:持续打印日志"""while True:print("守护进程运行中...")time.sleep(1)def normal_task():"""普通进程任务:执行3秒后结束"""time.sleep(3)print("普通进程结束")if __name__ == '__main__':# 创建守护进程(daemon=True)daemon_proc = multiprocessing.Process(target=daemon_task)daemon_proc.daemon = True  # 标记为守护进程# 创建普通进程normal_proc = multiprocessing.Process(target=normal_task)# 启动进程daemon_proc.start()normal_proc.start()# 主进程等待普通进程结束(3秒后)normal_proc.join()print("主进程结束")# 主进程结束后,守护进程会被自动终止(不会继续打印)# 结果:
# 守护进程运行中...
# 守护进程运行中...
# 守护进程运行中...
# 普通进程结束
# 主进程结束
  • 上述代码中,守护进程原本会无限循环打印,但主进程在普通进程结束后退出,守护进程被强制终止,不再输出。

进程间通信

  • 在计算机领域,IPC(Inter-Process Communication,进程间通信)是指操作系统中不同进程(运行中的程序)之间交换数据、传递信号或协调行为的技术机制。
  • 由于进程在内存中拥有独立的地址空间(为了安全性和隔离性),进程之间不能直接访问彼此的内存,因此需要通过操作系统提供的专门接口实现通信。
  • Python 的multiprocessing(队列、管道)模块封装了多种 IPC 工具,简化了进程间数据传递和协同的操作。

管道(Pipe):双向数据传递

  • 管道是半双工的,数据只能向一个方向流动,需要双方通信时,需要建立起两个管道
  • subprocess中Popen执行命令后的 stdout 和stderr 就是管道
  • 将消息放入到管道中之后只能从管道中读取一次消息
特点:

适用于两个进程之间的通信(一对一);
数据传递是双向的(全双工);
底层基于操作系统的管道机制,速度较快;
需注意:若两个进程同时读写,可能导致数据混乱,需手动同步(如加锁)。

import multiprocessingdef sender(conn):# 发送数据conn.send("Hello from sender")conn.send(123)conn.close()  # 关闭连接def receiver(conn):# 接收数据(recv()会阻塞直到有数据)print(conn.recv())  # 输出:Hello from senderprint(conn.recv())  # 输出:123conn.close()if __name__ == '__main__':# 创建管道,返回两个连接对象conn1, conn2 = multiprocessing.Pipe()# 创建发送和接收进程,分别传入不同的连接对象p_send = multiprocessing.Process(target=sender, args=(conn1,))p_recv = multiprocessing.Process(target=receiver, args=(conn2,))p_send.start()p_recv.start()p_send.join()p_recv.join()

队列(Queue):多进程安全的数据缓冲

  • 队列是一个 “先进先出(FIFO)” 的缓冲容器,由multiprocessing.Queue()创建。多个进程可通过put()向队列放入数据,或通过get()从队列取出数据,底层基于管道和锁实现,保证了线程和进程安全。
  • 将数据扔到队列中 由另一个进程不断地获取数据即可
特点:

适用于多个进程(多生产者、多消费者)之间的通信;
无需手动处理同步(内部已加锁);
支持阻塞/非阻塞操作(如get(block=False)非阻塞取数据,无数据时抛异常);
JoinableQueue是增强版队列,支持task_done()和join(),可等待队列中所有任务处理完成。

import multiprocessing
import timedef producer(q, name):"""生产者:向队列放数据"""for i in range(3):data = f"{name}的数据{i}"q.put(data)print(f"{name}生产:{data}")time.sleep(0.5)  # 模拟耗时def consumer(q, name):"""消费者:从队列取数据"""while True:data = q.get()  # 阻塞等待数据if data is None:  # 终止信号breakprint(f"{name}消费:{data}")time.sleep(1)  # 模拟处理耗时q.task_done()  # 通知队列该任务已处理(仅JoinableQueue需要)if __name__ == '__main__':# 创建可等待的队列(适合需要确认任务完成的场景)q = multiprocessing.JoinableQueue()# 创建2个生产者、2个消费者producers = [multiprocessing.Process(target=producer, args=(q, f"生产者{i}"))for i in range(2)]consumers = [multiprocessing.Process(target=consumer, args=(q, f"消费者{i}"))for i in range(2)]# 启动所有进程for p in producers:p.start()for c in consumers:c.start()# 等待所有生产者完成for p in producers:p.join()# 向队列发送终止信号(每个消费者一个)for _ in consumers:q.put(None)# 等待所有消费者处理完数据for c in consumers:c.join()# 等待队列中所有任务完成q.join()print("所有任务处理完毕")

有关信号可以点击阅读另一篇博客。

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

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

相关文章

QT:键盘事件(添加资源图片)

通过键盘的上、下、左、右方向键可以控制图标的移动,移动的步进值 为风格的大小,如果 同时按下CTRL键,则实现细微移动;若按下HOME键,则光标回到界面的左上顶点;若按下 END键,则光标到达界面的右下顶点。键盘事件…

2025.10.28

依旧早八一天课,晚上开会,累累的

docker desktop:更新WSL2+安装nginx

1.打开Windows系统的虚拟化(任务管理器内的CPU栏可以查看对应情况) 如果没开,查电脑型号去bios打开搜索启用或关闭Windows功能,打开下面两项 2.官网下载docker desktop,正常步骤安装,记得勾选WSL2 3.解决WSL问题…

# 学代码--看懂了但是不会写

1.1 怎么回事啊 !!! 在学习书上或者网上的代码的时候,经常会出现一种困惑:那就是初看代码,诶,我好像懂了诶。 但是要开始写的时候,就比较难下手了。我这个时候经常想:我刚刚,不是学过了吗?没学会吗哈哈哈哈…

2025-10-28 aoao Round 比赛总结

比赛链接 比赛时的状态 be like:我靠,这题怎么这么难?T1 就开始上难度了? 没一道题会写,不会要爆零然后遗憾离场了吧? (想了 2147483647 种 T1 的假做法) (去体检,在测血压时)等会,我好像想明白 T1 的本质了…

P11307 [COTS 2016] 建造费 Pristojba 分析

题目概述 这是一个 \(n\) 个点的无向图 \(G\),然后给你 \(m\) 次操作。 给你每个点的点权 \(p_i\),定义一条边 \((i,j)\) 的边权为 \(p_i+p_j\) 每个操作对应 \((x,l,r)\) 保证 \(x\notin [l,r]\)。 然后对于所有的 …

程序员如何打破职业瓶颈?先搬开这3块绊脚石。

程序员的职业路不算长,可不少人早早就遇到了 “天花板”:想提升没方向,想突破没抓手,这就是让人头疼的 “瓶颈期”。是什么让我们陷入这种困境?又该怎么走出来?咱们一点点说清楚。 摆烂心态 在程序员不算长的职业…

文件清理,推荐几款常用软件

文件清理,推荐几款常用软件给大家汇总如下表格,根据自己的情况自行选择: 您的资助是我最大的动力!金额随意,欢迎来赏!付款后有任何问题请给我留言。 如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的…

AI时代的设计师:从工具到“超人”的进化之路

最近刷到几则关于AI和设计领域的新闻,感觉挺有意思的。站酷发布了AI设计Agent,美图CEO吴欣鸿在演讲中提到AI正让设计师变成“超人”,而另一边,Meta的裁员风波又让人对AI行业的就业前景捏把汗。先说说AI工具如何改变…

MyBatis 动态 SQL 实现原理 - Higurashi

总结自(部分调整):MyBatis 3 源码深度解析SqlSource 与 BoundSql 详解 在介绍原理之前,我们首先需要了解 MyBatis 中和 SQL 语句有关的两个组件,即 SqlSource 和 BoundSql。SqlSource:代表 Java 注解或者 XML 文…

bililun

实验任务1 源代码 T.cpp#include "T.h" #include <iostream> #include <string>// 类T实现// static成员数据类外初始化 const std::string T::doc{"a simple class sample"}; const…

《程序员修炼之道:从小工到专家》观后感第二篇

《代码之美——DRY原则与简洁代码的实效哲学》 核心观点:“不要重复自己(DRY)”是编码的黄金法则,冗余代码会直接推高维护成本与bug发生率,而简洁、自解释的代码是系统可维护性的核心保障。 案例分析:某社交平台…

【学习笔记】数据结构全家桶

Data Structure前言 2025.10.28: 一时兴起建了这个,原因是刚刚学了KTT qwq 我如果塞完这个东西应该都大学几年级了吧 没事慢慢弄 正文 线段树 KTT点我展开看代码 #include<bits/stdc++.h> #define rep(i, l, r…

社区

社区报告名称:AR(Active Area Reverse)fin cut工艺参数与表征指标数据分析报告 版本:V1.0 日期:2025-09-05 编制人:李晓睿 审核人:[姓名/部门] 1. 数据收集报告 1.1 数据来源来源:AR(AA Reverse)fin cut工艺…

「Gym 102759I」Query On A Tree 17

题目大意 给定一颗 \(N\) 个节点以 \(1\) 为根的有根树,每次给以 \(u\) 为根的子树每点加 \(1\) 的值或给路径 \(u - v\) 上每点加 \(1\) 的值,每次修改后查询一个点 \(u\) 使得 \(\sum_{v = 1}^N dis(u, v)\) 最小。…

Mybatis使用简述

什么是 MyBatis? MyBatis 是一款优秀的 Java 持久层框架,它通过 XML 或注解的方式将 Java 对象与数据库中的记录进行映射。与传统的 JDBC 相比,MyBatis 极大地简化了数据库操作代码,让开发者能够更专注于业务逻辑而…

重组蛋白表达服务:CHO HEK293细胞系选择与表达优化方案

重组蛋白表达服务:CHO/HEK293细胞系选择与表达优化方案在生命科学研究领域,重组蛋白作为重要的科研试剂,其质量直接影响实验结果的可靠性。选择合适的表达系统并进行表达优化,是获得高质量重组蛋白的关键环节。本文…

C++里的代码命名规范

以下是 C++ 中最主流的几种命名规范: 1. 蛇形命名法 这是 C++ 标准库和许多 C++ 社区(如 Boost)最推荐的风格。小写蛇形命名法:所有字母小写,单词之间用下划线 _ 连接。适用于:变量、函数、命名空间、文件。 示例…

最小二乘问题详解6:梯度下降法

介绍了使用梯度下降法求解非线性最小二乘问题的原理与实现,通过C++和Eigen库对指数模型进行参数拟合,展示了算法流程、雅可比矩阵计算及收敛行为,并对比了其在机器学习与计算机视觉中的应用差异。1. 引言 在之前的两…