Python--进程基础

news2025/1/15 13:04:48

创建进程

os.fork()

该方法只能在linux和mac os中使用,因为其主要基于系统的fork来实现。window中没有这个方法。

通过os.fork()方法会创建一个子进程,子进程的程序集为该语句下方的所有语句。

 import os
 ​
 ​
 print("主进程的PID为:" , os.getpid())
 w = 1
 pid = os.fork() # 创建子进程
 print('fork方法的返回值为: ', pid)
 if pid == 0:
     print(f'子进程PID: {os.getpid()}, 主进程PID: {os.getppid()}, 子进程中w: {w}')
 else:
     print(f'主进程PID: {os.getpid()}, 主进程PID: {os.getppid()}, 子进程中w: {w}')

multiprocessing(target为函数)

通过multiprocessing模块中的Process类创建一个进程实例对象,并通过其start方法启动该进程。

进程中的程序集为Process类的target参数,可以是一个函数也可以是一个方法。

需要注意的是windows系统中创建进程的过程需要放在if __name__== "__main__"代码块中,因为其实现数据集的复制时,是通过import语句实现。

而在Linux和MacOS系统下则不需要,因为他们原生支持fork方法。

 import multiprocessing
 import os
 import time
 ​
 def task():
     for i in range(3):
         print("wating... 当前pid为 : ", os.getpid(), "父进程为: ", os.getppid())
         time.sleep(1)
 ​
 ​
 ​
 if __name__ == "__main__":
     print('主进程pid:', os.getpid())
 ​
     process = multiprocessing.Process(target=task)
     process.start()

multiprocessing(taget为方法)

创建Process实例对象的target参数,不仅可以是函数名,还可以是类的方法名。

  • 如果需要往target中传入参数,可以通过args和kwargs两个参数进行相应的传参
 import multiprocessing
 import time
 ​
 class Tasks():
     def task1(self):
         time.sleep(1)
         print('task1')
 ​
     def task2(self):
         time.sleep(1)
         print('task2')
 ​
 if __name__ == "__main__":
     t = Tasks()
     process1 = multiprocessing.Process(target=t.task1)
     process1.start()
 ​
     process2 = multiprocessing.Process(target=t.task2)
     process2.start()
     

继承Process类

通过继承multiprocessing.Process类,并重写其中的run方法。

  • 必须要重写run方法,Process子类的实例对象的run方法,就是进程执行的程序
 import time
 from multiprocessing import Process
 ​
 ​
 class MyProcess(Process):
     def __init__(self, i):
         super().__init__()
         self.name = str(i)
 ​
     def run(self):
         time.sleep(2)
         print(f'子进程-{self.name}')
 ​
 ​
 if __name__ == '__main__':
     for i in range(5):
         p = MyProcess(i)
         p.start()
 ​
     print('主进程')

进程阻塞

目前系统一般都是多核的,当处理多任务时,一般都以并发或并行的方式处理多任务。所以系统一般以异步的方式处理多进程。

Process的实例方法中,通过join方法表示进程阻塞时,主将处于等待状态,并不会处理其他进程。

单进程阻塞

针对每个进程开启后立马启用join方法,这种方法效率低下。使得系统的处理方式编程同步阻塞,使得主进程依次处理子进程。

 import time
 from multiprocessing import Process
 ​
 def eat():
     time.sleep(2)
     print('eat')
 ​
 def drink():
     time.sleep(2)
     print('drink')
 ​
 if __name__ == '__main__':
     process1 = Process(target=eat)
     process1.start()
     process1.join()
 ​
     process2 = Process(target=drink)
     process2.start()
     process2.join()
 ​
 ​
     print('主进程')

多进程阻塞

先利用start方法将多个进程同时创建并启动,然后在创建完成后统一阻塞进程。

  • 统一创建进程,并让其统一运行
  • 统一等待进程结束,避免每个进程都等一段时间
 import time
 from multiprocessing import Process
 ​
 def eat():
     time.sleep(2)
     print('eat')
 ​
 def drink():
     time.sleep(2)
     print('drink')
 ​
 ​
 ​
 if __name__ == '__main__':
     process1 = Process(target=eat)
     process1.start()
 ​
     process2 = Process(target=drink)
     process2.start()
 ​
     for p in [process1, process2]:
         p.join()
 ​
     print('主进程')

进程锁

当多进程编辑同一文件或数据时,往往会导致数据不一致问题,针对这种情况,需要在进程中对处理文件或数据的代码前后进行加锁和解锁操作。

如果没有锁,会导致数据的不一致

 import time, json
 from multiprocessing import Process
 ​
 ​
 def read_ticket(user):
     with open('ticket.txt') as f:
         num = json.load(f)['ticket']
         time.sleep(1)
         print(f'User {user}: 当前剩余{num}张票')
         return num
 ​
 ​
 def order_ticket(user, num):
     time.sleep(1)
     num -= 1
     with open('ticket.txt', 'w') as f:
         json.dump({'ticket': num}, f)
     print(f'User {user}: 购票成功')
 ​
 ​
 def ticket(user):
     num = read_ticket(user)
     if num > 0:
         order_ticket(user, num)
     else:
         print(f'User {user}: 购票失败')
 ​
 ​
 if __name__ == '__main__':
     queue = []
     for i in range(5):
         p = Process(target=ticket, args=(i,))
         p.start()
         queue.append(p)
     for q in queue:
         q.join()
 ​
     print('运行结束')

加锁/解锁

在编辑数据的之前通过acquire方法加锁,当数据编辑完成后,通过release方法解锁。

  • 在主进程中创建一个锁对象
  • 然后在每个修改共同数据的进程中传入已经创建的锁对象
  • 在修改数据的代码前后分别加锁和解锁
 """
 @Time: 2024/6/28 20:18
 @Author: 'Ethan'
 @Email: ethanzhou4406@outlook.com
 @File: 1. 同步阻塞.py
 @Project: python
 @Feature:
 """
 import time, json
 from multiprocessing import Process, Lock
 ​
 ​
 def read_ticket(user):
     with open('ticket.txt') as f:
         num = json.load(f)['ticket']
         time.sleep(0.1)
         print(f'User {user}: 当前剩余{num}张票')
 ​
 ​
 def order_ticket(user):
     time.sleep(0.1)
     with open('ticket.txt') as f:
         num = json.load(f)['ticket']
     if num > 0:
         with open('ticket.txt', 'w') as f:
             num -= 1
             json.dump({'ticket': num}, f)
         print(f'User {user}: 购票成功')
     else:
         print(f'User {user}: 购票失败')
 ​
 ​
 def ticket(user,lock):
     read_ticket(user)
     lock.acquire()
     order_ticket(user)
     lock.release()
 ​
 ​
 if __name__ == '__main__':
     lock = Lock()
     queue = []
     for i in range(5):
         p = Process(target=ticket, args=(i, lock))
         p.start()
         queue.append(p)
     for q in queue:
         q.join()
 ​
     print('运行结束')
 ​

锁的上下文管理器

如果在代码加锁后,解锁前,代码出现了异常就会导致进程没有来得及解锁,而导致死锁现象。通过锁的上下文管理器语法,可以有效避免这种情况的发生。

 import time, json
 from multiprocessing import Process, Lock
 ​
 ​
 def read_ticket(user):
     with open('ticket.txt') as f:
         num = json.load(f)['ticket']
         time.sleep(0.1)
         print(f'User {user}: 当前剩余{num}张票')
 ​
 ​
 def order_ticket(user):
     time.sleep(0.1)
     with open('ticket.txt') as f:
         num = json.load(f)['ticket']
     if num > 0:
         with open('ticket.txt', 'w') as f:
             num -= 1
             json.dump({'ticket': num}, f)
         print(f'User {user}: 购票成功')
     else:
         print(f'User {user}: 购票失败')
 ​
 ​
 def ticket(user,lock):
     read_ticket(user)
     with lock:
         order_ticket(user)
 ​
 ​
 if __name__ == '__main__':
     lock = Lock()
     queue = []
     for i in range(5):
         p = Process(target=ticket, args=(i, lock))
         p.start()
         queue.append(p)
     for q in queue:
         q.join()
 ​
     print('运行结束')
 ​

进程间通信

进程之间可以进行通信,主要是通过各个进程之中传入一个公共的沟通工具,所有的进程都通过这个工具进行沟通。multiprocessing中提供了两种进程间沟通的工具QueuePipe

Queue方式

Queue是基于文件传输的socket通信方式,并且它是带锁机制的。它的数据主要的特点是先进先出,后进后出。

当一个对象被放入一个队列中时,这个对象首先会被一个后台线程用pickle序列化,并将序列化后的数据通过一个底层管道的管道传递给队列中。

主要使用如下方法:

  • qsize(): 返回队列的大致的长度。返回的值由于多线程或多进程的上下文而变得不可靠
  • empty(): 队列为空返回True,否则返回False。返回的值由于多线程或多进程的上下文而变得不可靠
  • full(): 队列满了返回True,否则返回False。返回的值由于多线程或多进程的上下文而变得不可靠
  • put(obj[, block[, timeout]]): 将obj放入队列。
    • 如果block为True(默认值)而且timeout是None(默认值),将会阻塞当前进程,直到有空的缓冲槽。
    • 如果timeout是正数,将会阻塞了最多timeout秒之后还是没有可用的缓冲槽时抛出queue.Full异常
    • 反之block为False,仅当有可用缓冲槽时才放入对象,否则抛出queue.Full异常(这种情况下timeout参数会被忽略)

  • get([block[, timeout]]): 从队列中取出并返回对象。如果可选参数block是True而且timeout是None,将会阻塞当前进程,直到队列中出现可用对象。如果timeout是正数,将会阻塞了最多timeout秒之后还是没有可用的对象时抛出queue.Empty异常。
    • 反之,block是False时,仅当有可用对象能够取出时返回,否则抛出queue.Empty异常(这种情况下timeout参数会被忽略)

 import time, json
 from multiprocessing import Process, Queue
 ​
 ​
 def task(i, queue: Queue):
     time.sleep(1)
     queue.put(i)
     print(f'task {i}, 入列')
 ​
 ​
 if __name__ == '__main__':
     queue = Queue()
     process_queue = []
     for i in range(5):
         p = Process(target=task, args=(i, queue))
         p.start()
         process_queue.append(p)
     for p in process_queue:
         p.join()
 ​
     for i in range(5):
         print(f'主进程中消费队列内容{queue.get()}')
 ​
     print('运行结束')
 ​

Pipe方式

Pipe方式是进程之间通信的另一种方式和Queue不同之处在于,它不带锁,且信息顺序无法得到保障。

主要的使用方法:

  • send(obj): 将一个对象发送到链接的另一端,可以用recv()读取,发送的对象必须是可序列化的,多大的对象(接近32MiB)可能引发ValueError异常
  • recv(): 返回一个由另一端使用send()发送的对象,该方法会一直阻塞直到接收到对象。如果对端关闭了链接或者没有东西可接收,将抛出EOFError异常
 import time
 from multiprocessing import Process, Pipe
 from multiprocessing.connection import Connection
 ​
 ​
 def task(pipe:Connection):
     print('子进程往管道里加了内容')
     time.sleep(1)
     pipe.send("子进程往管道中加了点东西")
 ​
 ​
 if __name__ == '__main__':
     pipe1, pipe2 = Pipe()
     p = Process(target=task, args=(pipe1,))
     p.start()
     p.join()
     print('主进程中获取管道内的内容为:', pipe2.recv())
     print('运行结束')

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

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

相关文章

零信任沙箱在数据安全领域的意义

在当今日益复杂的网络安全环境中,零信任沙箱作为一种前沿的安全防护技术,受到了广泛关注。而SDC沙箱作为零信任沙箱领域的佼佼者,凭借其独特的技术优势和卓越的价值,为企业和组织提供了强大的数据安全保障。本文将深入探讨SDC沙箱…

全面升级厨房安全,电焰灶引领新时代

煤气是许多家庭日常使用的能源,目前的普及率还是比较高的,但平时因煤气泄漏而引发的事故也很多,只需要查看最近一个月因液化气泄漏引起的爆炸事件屡见不鲜。打开新闻,我们总能时不时看到煤气爆炸的事故,幸运的能够逢凶…

USB PD+TYPE -C快充电源中MOSFET选型,USB PD应用市场包含智能手机,平板电脑,笔记本电脑,游戏本,移动硬盘,数码相机,电动工具等传统领域

USB PD全称为USB Power Delivery,是由USB-IF组织制定的一种快速充电协议,也是目前市场非常看好的一种协议,可以支持输出功率高达100W;Type-C是一种接口规范,能够支持传输更大的电流。USB PD应用市场不仅包含智能手机&a…

uniapp微信小程序使用xr加载模型

1.在根目录与pages同级创建如下目录结构和文件: // index.js Component({properties: {modelPath: { // vue页面传过来的模型type: String,value: }},data: {},methods: {} }) { // index.json"component": true,"renderer": "xr-frame&q…

JVM原理(二):JVM之HotSpot虚拟机中对象的创建寻位与定位整体流程

1. 对象的创建 遇到new指令时 当Java虚拟机遇到一个字节码new指令时。 首先会去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否被加载、解析和初始化过。 如果没有,那么必须执行类的加载过程(加载、检查…

面向工业化的多类电子元件自动计数系统测试报告

目录 1、项目描述 2、登录注册测试 2、主界面测试 2.1、在线计数测试 2.2、离线计数测试 2.3、浏览数据测试 1、项目描述 该系统利用机器视觉平台采集电子元件图像,设计并实现了适应不同形态分布的电子元件计数模型,能够快速且准确地进行计数和分类&…

Unity海面效果——3、漫反射颜色和水波

Unity引擎制作海面效果 大家好,我是阿赵。 之前介绍了菲涅尔水的反射区域区分做法,上一次最后是做到了这个效果,接下来做一下漫反射的颜色和水波。 一、 漫反射颜色 关于漫反射的光照模型,之前分享过,一般比较常用的是…

SSM OA办公系统19159

SSM OA办公系统 摘 要 随着现代信息技术的快速发展以及企业规模不断扩大,实现办公线上流程自动化已成为提升企业核心竞争力的关键。本文主要介绍的是利用Spring、SpringMVC和MyBatis(简称为:SSM)框架,MySQL数据库等先…

如果这时你还不清理C盘,那只能眼睁睁看着电脑越来越卡 直到系统崩溃

如果这时候你还不清理C盘,那只能眼睁睁看着电脑越来越卡 直到系统崩溃。很多人就是想偷懒,当然这是人的天性,明明知道自己的C盘空间就那么大,一天天看着C盘空间越来越小,还不去清理C盘。 这样的人有两种,一…

【计算机毕业设计】基于Springboot的大学生就业招聘系统【源码+lw+部署文档】

包含论文源码的压缩包较大,请私信或者加我的绿色小软件获取 免责声明:资料部分来源于合法的互联网渠道收集和整理,部分自己学习积累成果,供大家学习参考与交流。收取的费用仅用于收集和整理资料耗费时间的酬劳。 本人尊重原创作者…

构建LangChain应用程序的示例代码:50、如何在检索-生成 (RAG) 应用中利用多模态大型语言模型 (LLM) 处理包含文本和图像的混合文档的示例

多模态 RAG 许多文档包含多种内容类型,包括文本和图像。 然而,大多数 RAG 应用中,图像中捕获的信息往往被忽略。 随着多模态 LLM 的出现,如 GPT-4V,值得考虑如何在 RAG 中利用图像: 选项 1:…

【Java面试场景题】微信抢红包的功能是如何实现的,如果让你来做你怎么设计?

一、问题解析 实现拼手气红包算法,有以下几个需要注意的地方: 抢红包的期望收益应与先后顺序无关保证每个用户至少能抢到一个预设的最小金额,人民币红包设置的最小金额一般是0.01元,如果需要发其他货币类型的红包,比…

云微客矩阵系统:如何利用智能策略引领营销新时代?

近些年,短视频行业的风头一时无二,大量的商家和企业进驻短视频赛道,都或多或少的实现了实体门店的流量增长。虽然说现在短视频的门槛在逐步降低,但是迄今为止依旧有很多人在短视频剪辑面前望而却步。 最近在短视频营销领域&#x…

3.js - 深度测试、深度写入、深度函数

md,艹,这玩意得理解,只看代码不管事 效果图 代码 // ts-nocheck// 引入three.js import * as THREE from three// 导入轨道控制器 import { OrbitControls } from three/examples/jsm/controls/OrbitControls// 导入lil.gui import { GUI } …

Git新仓库创建流程

平时需要创建新仓库,老要去查代码特别烦,在此写下流程方便备用. 1.创建新的云仓库 无论使用GitHub还是Gitee,首先要创建一个云仓库,这里就直接用国内的gitee做演示了,githup老挂加速器太烦,偷个懒. 我这里创建的是一个空仓库&…

DLS-42/5-5双位置继电器 DC220V 板后接线 约瑟JOSEF

DLS-40系列双位置继电器型号: DLS-41/10-2双位置继电器; DLS-41/9-3双位置继电器 DLS-41/8-4双位置继电器; DLS-41/6-6双位置继电器; DLS-42/9-1双位置继电器; DLS-42/8-2双位置继电器; DLS-42/7-3双位…

教师工作经历轻松管理,智慧校园人事系统助您事半功倍

智慧校园人事系统中的教师工作经历管理模块,是一个集记录、跟踪、分析于一体的综合平台,专注于教师职业生涯的全貌管理,从初次入职到每一次岗位变动、学术成就及专业发展轨迹,旨在为学校提供一个全面了解教师专业成长、优化师资配…

能自动铲屎的养猫救星?带你了解热门爆款智能猫砂盆的真实体验!

在谈论猫咪的日常生活时,我和朋友最经常聊的话题就是在各种各样的紧急情况下如何狼狈地赶回去给猫咪铲屎,毕竟猫砂盆里的屎但凡停留那么几小时,就要开始发臭了,一下班回去实在受不了那个味道,每次下班在家门口都想带个…

mac有什么解压软件 mac怎么解压7z软件 苹果电脑好用的压缩软件有哪些

众所周知,macOS集成解压缩软件归档实用工具,可直接解压zip格式的压缩包。但对于其他比较常见的格式,诸如RAR、7z、TAR等,则无能为力,不过,我们可以选择大量第三方解压缩软件,帮助我们更好地完成…