python中的进程间通信

进程间数据是否共享

在Python中,进程之间默认是不共享内存的。每个进程都有自己独立的内存空间,这意味着在一个进程中对数据的修改不会影响到另一个进程中的同名数据。然而,Python提供了几种方式来实现进程间的数据共享:

  1. 使用 multiprocessing 模块: Python 的 multiprocessing 模块提供了多种方式来实现进程间通信(IPC),其中包括:

    • Value 和 Array: 可以用于存储数据并可以被多个进程共享。
    • Manager: 通过使用 manager 对象,可以创建一个运行在服务器进程中的管理器对象,该对象支持将列表、字典等放在多个进程之间共享。
  2. 使用文件或数据库: 进程可以通过读写文件或操作数据库来交换信息。这种方法相对简单但可能受到I/O性能限制。

  3. 使用消息传递机制:如队列(Queue)和管道(Pipe),这些也是 multiprocessing 提供的功能。它们允许将消息从一个进程传递到另一个,虽然严格意义上不是共享内存,但它们是进行数据交换和任务协调非常有效的手段。

下面是一个简单示例代码说明,在不使用Value的情况下

from multiprocessing import Process, Lock, current_process
import time


def process_with_shared_resource(shared_resource, lock):
    name = current_process().name
    lock.acquire()
    try:
        print(f"{name} 获取当前共享变量: {shared_resource}")
        shared_resource += 1
        time.sleep(0.1)
        print(f"{name} 更新后的共享变量: {shared_resource}")
    finally:
        lock.release()


if __name__ == "__main__":
    # 创建一个共享的资源和锁
    shared_resource = 0
    lock = Lock()

    # 创建多个进程
    processes = []
    for _ in range(5):
        p = Process(target=process_with_shared_resource, args=(shared_resource, lock))
        processes.append(p)
        p.start()

    # 等待所有进程完成
    for p in processes:
        p.join()

    print(f"最终变量值: {shared_resource}")

输出:

Process-3 获取当前共享变量: 0
Process-3 更新后的共享变量: 1
Process-1 获取当前共享变量: 0
Process-1 更新后的共享变量: 1
Process-2 获取当前共享变量: 0
Process-2 更新后的共享变量: 1
Process-4 获取当前共享变量: 0
Process-4 更新后的共享变量: 1
Process-5 获取当前共享变量: 0
Process-5 更新后的共享变量: 1
最终变量值: 0

看到,每个进程都有自己的变量shared_resource,并且初始化值都为0。

优化使用Value后:

from multiprocessing import Process, Lock, current_process, Value
import time


def process_with_shared_resource(shared_resource, lock):
    name = current_process().name
    lock.acquire()
    try:
        print(f"{name} 获取当前共享变量: {shared_resource.value}")
        shared_resource.value += 1
        time.sleep(0.1)
        print(f"{name} 更新后的共享变量: {shared_resource.value}")
    finally:
        lock.release()


if __name__ == "__main__":
    # 创建一个共享的资源和锁
    shared_resource = Value('i', 0)
    lock = Lock()

    # 创建多个进程
    processes = []
    for _ in range(5):
        p = Process(target=process_with_shared_resource, args=(shared_resource, lock))
        processes.append(p)
        p.start()

    # 等待所有进程完成
    for p in processes:
        p.join()

    print(f"最终变量值: {shared_resource.value}")

输出:

Process-1 获取当前共享变量: 0
Process-1 更新后的共享变量: 1
Process-4 获取当前共享变量: 1
Process-4 更新后的共享变量: 2
Process-5 获取当前共享变量: 2
Process-5 更新后的共享变量: 3
Process-2 获取当前共享变量: 3
Process-2 更新后的共享变量: 4
Process-3 获取当前共享变量: 4
Process-3 更新后的共享变量: 5
最终变量值: 5

结果正确了

进程间通信

在前面的学习中我们提到了一个概念,就是主进程的代码执行结束以后,主进程并没有结束的,因为主进程需要等待所有子进程运行代码结束以后,主进程通过系统调用回收子进程的资源,紧接着主进程才进行系统调用回收当前进程的资源。

那么,主进程怎么在数据隔离的情况下知道每一个子进程是什么时候结束的呢?

注意:子进程是完全有可能存在input,recv这样的阻塞代码情况的。实际上,父进程不可能预判到每个子进程什么时候结束的,但是可以让子进程在结束的时候发出一个信号告诉父进程,它结束了。父进程接受到该子进程的结束信号就可以通过系统调用回收子进程的资源了。而这个发出信号与接收信号的过程,就是进程间的通信(IPC)了。

进程间通信(Inter-Process Communication,IPC)是操作系统中允许不同进程之间交换信息的一种机制。在多任务操作系统中,IPC对于实现不同程序组件之间的协作至关重要。由于每个进程都有自己独立的内存空间,所以他们不能直接共享内存中的数据。Python提供了多种机制来实现进程间的通信,主要通过 multiprocessing 模块来完成。

1. 管道(Pipes)

管道是一种最基本的进程间通信方式。在Python中,multiprocessing 模块的 Pipe() 函数可以创建一对连接对象,这两个对象可以在不同进程间通过发送和接收消息来通信。管道可以是单向的(半双工)或双向的(全双工)。

  1. 创建管道:调用multiprocessing.Pipe()将创建一对可以用于进程间通信的文件描述符。

  2. 读写通信:一个进程使用一个文件描述符的一端来发送数据,另一个进程使用另一个文件描述符的另一端来接收数据。

  3. 半双工通信:数据只能在一个方向上流动,这意味着发送方和接收方不能同时发送数据,但可以交替进行。

  4. 关闭管道:通信完成后,应该关闭管道以释放系统资源。

from multiprocessing import Process, Pipe, current_process


def child(conn):
    str_send = "Hello ~"
    print(f'{current_process().name} 发送消息:{str_send}')
    conn.send(str_send)
    conn.send(str_send)
    conn.close()


if __name__ == '__main__':
    parent_conn, child_conn = Pipe()
    p = Process(target=child, args=(child_conn,))
    p.start()

    # recv会阻塞调用,直到收到消息
    print(f"{current_process().name} 接受到消息:{parent_conn.recv()}")
    print(f"{current_process().name} 接受到消息:{parent_conn.recv()}")
    # print(f"{current_process().name} 接受到消息:{parent_conn.recv()}") # 阻塞接受消息

    parent_conn.close()  # 关闭父进程端的管道
    p.join()  # 等待子进程结束

  • 我们定义了一个child函数,它将通过管道发送一条消息。
  • 在主进程中,我们创建了一个管道,并将管道的两个端点分别赋值给parent_connchild_conn
  • 我们创建了一个子进程,并将child_conn传递给它。
  • 子进程开始运行,并调用child函数,通过管道发送了一条消息。
  • 主进程使用parent_conn.recv()来接收消息,然后打印这条消息。
  • 最后,我们关闭了管道,并等待子进程结束。

注意,multiprocessing.Pipe()主要用于进程间的通信,而不是线程间的通信。

2. 队列(Queues)

队列是用于多个生产者(发送者)和消费者(接收者)的典型场景。它是线程和进程安全的。通过使用 multiprocessing.Queue,可以在进程间安全地交换消息或其他数据。

from multiprocessing import Process, Queue, current_process


def worker(queue):
    while True:
        args = queue.get()  # 阻塞调用,直到队列中有数据
        # 这里可以处理接收到的参数
        print(f"{current_process().name} 接受到消息到: {args}")
        if args is None:  # 接收到退出信号
            break


if __name__ == '__main__':
    # 创建一个队列
    q = Queue()

    # 启动一个工作进程
    p = Process(target=worker, args=(q,))
    p.start()

    # 将数据放入队列
    for i in range(10):
        print(f"{current_process().name} 发送消息: {i}")
        q.put(i)

    q.put(None)

    # 等待队列中的所有任务被处理完成
    p.join()

    print("结束")

3. 共享内存

multiprocessing 模块还支持通过共享内存来进行进程间通信,主要通过 ValueArray。这允许创建一个可以在多个进程间共享的变量。

最开始的代码例子便使用的是Value模块

4. 管理器(Managers)

multiprocessing 提供了一个 Manager() 方法,用于创建一个管理器对象,该对象支持将Python对象放在服务器进程中,以便不同进程可以通过代理的方式访问。

from multiprocessing import Process, Manager, current_process


def f(d, l):
    d[1] = '1'
    d['2'] = 2
    d[0.25] = None
    l.reverse()


if __name__ == '__main__':
    with Manager() as manager:
        d = manager.dict()
        l = manager.list(range(10))
        print(f"{current_process().name} dict: {d}")
        print(f"{current_process().name} list: {l}")

        p = Process(target=f, args=(d, l))
        p.start()
        p.join()

        print(f"{current_process().name} dict: {d}")
        print(f"{current_process().name} list: {l}")
        # 子进程已经修改了变量

输出:

MainProcess dict: {}
MainProcess list: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
MainProcess dict: {1: '1', '2': 2, 0.25: None}
MainProcess list: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

进程间的数据隔离

进程间的数据隔离是操作系统设计中的一个核心概念,它确保了不同进程的内存空间和数据是相互独立的,从而防止了进程间的非授权数据访问和潜在的数据冲突。以下是实现进程间数据隔离的一些关键机制:

  1. 独立的地址空间

    • 每个进程都有自己独立的虚拟地址空间,这意味着一个进程的代码和数据不能直接被另一个进程访问。
  2. 内存保护

    • 操作系统通过内存保护机制防止进程访问不属于它的内存区域。如果一个进程尝试访问另一个进程的内存,操作系统将触发一个保护错误(通常是段错误)。
  3. 分页机制

    • 操作系统使用分页机制来管理内存,每个进程的页表是独立的,映射到物理内存的地址也是不同的。
  4. 执行上下文

    • 每个进程都有自己的执行上下文,包括程序计数器、堆栈指针、寄存器集合等,这些上下文在进程切换时会保存和恢复。
  5. 文件描述符和文件权限

    • 进程对文件的访问是通过文件描述符进行的,操作系统通过文件权限来控制进程对文件的访问。
  6. 系统调用

    • 进程需要通过系统调用来请求操作系统提供的服务,如内存分配、文件操作等,这些系统调用会进行必要的安全检查。
  7. 用户和组ID

    • 每个进程都有一个用户ID(UID)和一个或多个组ID(GID),操作系统使用这些ID来控制进程对资源的访问权限。
  8. 命名空间

    • 现代操作系统(如Linux)使用命名空间来提供更细粒度的隔离,包括PID命名空间、网络命名空间、挂载命名空间等。
  9. 安全模块和沙箱

    • 操作系统和应用程序可以使用安全模块和沙箱技术来进一步限制进程的权限和行为。
  10. 权限控制

    • 进程的权限受到其用户权限和组权限的限制,操作系统会根据这些权限来控制进程可以执行的操作。
  11. AppArmor或SELinux

    • 这些是Linux系统中的强制访问控制系统,它们可以提供更细粒度的访问控制和隔离。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MMSeg搭建模型的坑

Input type(torch.suda.FloatTensor) and weight type (torch.FloatTensor) should be same 自己搭建模型的时候,经常会遇到二者不匹配,以这种情况为例,是因为部分模型没有加载到CUDA上面造成的。 注意搭建模型的时候,所有层都应…

Oracle之RMAN联机和脱机备份(二)

rman脱机备份,首先使用rman登入数据库服务器,然后关闭数据库后,启动数据库到mount状态,在执行backup database指定备份整个数据库。 1、启动mount归档模式 sys@ORCL>archive log list; Database log mode Archive Mode Automatic archival Enabl…

STM32H750外设ADC之开始和结束数据转换功能

目录 概述 1 开始转换 1.1 使能ADSTART 1.2 使能JADSTART 1.3 ADSTART 通过硬件清零 2 转换时序 3 停止正在进行的转换( ADSTP、 JADSTP) 3.1 停止转换功能实现 3.2 停止转换流程图 概述 本文主要讲述了STM32H750外设ADC之开始和结束数据转换…

SPRD Android 14 通过属性控制系统设置显示双栏或者单栏

SPRD Android 14 通过属性控制系统设置显示双栏或者单栏 第一步 确认有添加静态库第二步 验证第三步 修改源码在合适的地方配置 ro.product.is_support_SettingsSplitEnabled 即可。第一步 确认有添加静态库 --- a/packages/apps/Settings/Android.bp +++ b/packages/apps/Set…

[集群聊天项目] muduo网络库

目录 网络服务器编程常用模型什么是muduo网络库什么是epoll muduo网络库服务器编程 网络服务器编程常用模型 【方案1】 : accept read/write 不是并发服务器 【方案2】 : accept fork - process-pre-connection 适合并发连接数不大,计算任…

Centos的一些基础命令

CentOS是一个基于开源代码构建的免费Linux发行版,它由Red Hat Enterprise Linux (RHEL) 的源代码重新编译而成。由于 CentOS是基于RHEL构建的,因此它与RHEL具有非常类似的特性和功能,包括稳定性、安全性和可靠性。并且大部分的 Linux 命令在C…

Apache Doris 2.x 版本【保姆级】安装+使用教程

Doris简介 Apache Doris 是一个基于 MPP 架构的高性能、实时的分析型数据库,以极速易用的特点被人们所熟知,仅需亚秒级响应时间即可返回海量数据下的查询结果,不仅可以支持高并发的点查询场景,也能支持高吞吐的复杂分析场景。基于…

COOIS 生产订单显示系统增强

需求说明:订单系统显示页面新增批量打印功能 增强点:CL_COIS_DISP_LIST_NAVIGATION -->TOOLBAR方法中新增隐式增强添加自定义打印按钮 增强点:BADI-->WORKORDER_INFOSYSTEM新增增强实施 实现位置:IF_EX_WORKORDER_INFOSYS…

频裂变加群推广强制分享引流源码

视频裂变加群推广强制分享引流源码,用户达到观看次数后需要分享给好友或者群,好友必须点击推广链接后才会增加观看次数。 引导用户转发QV分享,达到快速裂变引流的效果! 视频裂变推广程序,强制分享链接,引导用户转发,…

数据库MySQL的初级基础操作

文章目录 1. 介绍2. 数据库相关概念3. 启动4. 数据模型5. SQL6. DDL数据库DDL-表操作DDL-表操作-数据类型DDL-表操作-修改DDL-表操作-删除 7. 图形化界面工具DataGrip8. DML(数据操作语言)DML-添加数据DML-修改数据 9. DQL(数据查询语言)基本查询条件查询…

MemFire案例-政务应急物联网实时监测预警项目

客户背景 党的十八大以来,中央多次就应急管理工作做出重要指示:要求坚持以防为主、防抗救相结合,全面提升综合防灾能力;坚持生命至上、安全第一,完善安全生产责任制,坚决遏制重特大安全事故。 面对新形势…

小白学习SpringCloud之Eureka

前言 需要搭建springcloud项目,eureka是其中的一个模块,依赖主要继承父依赖 学习视频:b站狂神说 便于理解,我修改了本地域名》这里!!! 127.0.0.1 eureka7001.com 127.0.0.1 eureka7002.com 127.0.0.1 eureka7003.comEureka入门案例 eureka…

Maven的仓库、周期和插件

一、简介 随着各公司的Java项目入库方式由老的Ant改为Maven后,相信大家对Maven已经有了个基本的熟悉。但是在实际的使用、入库过程中,笔者发现挺多人对Maven的一些基本知识还缺乏了解,因此在此处跟大家简单地聊下Maven的相关内容&#xff0c…

如何把经验变成可以销售的“知识产品”?

知识付费,很多人想做,但是不知道如何把自己在某方面的“经验”,变成一个“知识产品”,那么这篇文章,我们就来聊聊如何从0打造一个知识产品 非常简单,一共六个步骤: 第一步:取名字&…

【深度学习】StabelDiffusion,Lora训练过程,秋叶包,Linux,SDXL Lora训练

文章目录 一、环境搭建指南二、个性化安装流程三、启动应用四、打开web五、开始训练 19.27服务器 一、环境搭建指南 打造一个高效且友好的开发环境,我们推荐使用以下简洁明了的中文资源: 项目源码获取: 通过以下命令轻松克隆项目及所有子模…

(一)Dataframes安装与类型 #Julia数据分析 #CDA学习打卡

目录 一. Julia简介 二. Dataframe构造方法 1)访问列的方式 (a)判断严格相等 i. 切片严格相等是true ii. 复制严格相等是false (b)判断相等 i. 切片相等是true ii. 复制相等是true 2)获取列名称 …

【Camera KMD ISP SubSystem笔记】CAM SYNC与DRQ③

DRQ什么时候调度Node去填写dependency ::Pipeline调度Node的sequenceId 0执行 Pipeline::ProcessRequest() { for (UINT nodeIndex 0; nodeIndex < m_orderedNodeCount ; nodeIndex) m_pDeferredRequestQueue->AddDef…

ROM修改进阶教程------如何去除安卓机型系统的开机向导 几种操作步骤解析

在和很多工作室定制化系统中。手机在第一次启动的时候系统都会进入设置向导,虽然可以设置手机的基本配置。但有很多客户需要去除手机的开机向导来缩短开机时间。确保手机直接进入工作状态。那么今天的教程针去除对开机向导的几种方法做个解析。机型很多版本不同。操作也有不同…

JS实现对用户名、密码进行正则表达式判断,网页跳转

目标&#xff1a;使用JS实现对用户名和密码进行正则表达式判断&#xff0c;用户名和密码正确时&#xff0c;进行网页跳转。 用户名、密码的正则表达式检验 HTML代码&#xff1a; <button type"submit" id"login-btn" /*onclick"login();alidate…

四川易点慧电子商务:抖音小店引领潮流,先进模式打造电商新标杆

在当下数字化浪潮中&#xff0c;电子商务行业如日中天&#xff0c;四川易点慧电子商务有限公司以其独特的视角和前瞻性的战略布局&#xff0c;成功在抖音小店领域崭露头角&#xff0c;成为行业内的佼佼者。本文将深入剖析四川易点慧电子商务的成功秘诀&#xff0c;以及其在抖音…
最新文章