Python基础语法(多进程开发进程建数据共享进程锁进程池)

news2024/11/15 2:10:53

 Python基础语法文章导航:

  1. Python基础(01初识数据类型&变量)
  2. Python基础(02条件&循环语句)
  3. Python基础(03字符串格式化&运算符&进制&编码)
  4. Python基础(04 基础练习题)
  5. Python数据类型(day05整型&布尔类型&字符串类型)
  6. Python数据类型(06列表&元组)
  7. Python数据类型(07集合&字典&浮点型&None)
  8. Python文件操作01(自动化测试文件相关操作)
  9. Python函数入门(08函数定义&参数&返回值)

  10. Python文件操作02(自动化测试文件相关操作)

  11. Python函数(10生成器&内置函数&推导式)

  12. Python函数(11自定义模块&第三方模块&内置模块)

  13. Python函数(12时间处理&正则表达式)

  14. Python函数(13面向对象)

  15. Python面向对象(15成员&成员修饰符)

  16. Python函数(16进程和线程)

  17. Python基础语法(17多线程&线程锁&单例模式)

目录

一.多进程开发

1. 进程介绍

2. 常见功能

(1)p.start()

(2)p.join()

(3)p.daemon = 布尔值

(4)进程的名称的设置和获取

(5)自定义进程类,直接将线程需要做的事写到run方法中。

(6)CPU个数,程序一般创建多少个进程?(利用CPU多核优势)

二. 进程间数据的共享

1.共享

2.交换

(1)Queues

(2)Pipes

 3. 进程锁

4. 进程池


一.多进程开发

        进程是计算机中资源分配的最小单元;一个进程中可以有多个线程,同一个进程中的线程共享资源;进程与进程之间则是相互隔离

Python中通过多进程可以利用CPU的多核优势,计算密集型操作适用于多进程。

1. 进程介绍

import multiprocessing

def task(arg):
    pass

def run():
    p1 = multiprocessing.Process(target=task, args=('XXX'), )
    #当前进程准备就绪,等待被CPU调度(工作单元其实是进程中的线程)
    p1.start()

if __name__ == '__main__':
    run()

2. 常见功能

进程的常见方法:

(1)p.start()

  当前进程准备就绪,等待被CPU调度(工作单元其实是进程中的线程)。

(2)p.join()

  等待当前进程的任务执行完毕后再向下继续执行

def task(arg):
    time.sleep(2)
    print("执行中...")

if __name__ == '__main__':
    multiprocessing.set_start_method("spawn")
    name=[]
    p1=multiprocessing.Process(target=task,args=('xxx',))
    p1.start()
    p1.join()
    time.sleep(2)
    print("继续执行...")
#执行中...
#继续执行...(过了2秒后出现)

(3)p.daemon = 布尔值

  守护进程(必须放在start之前)

  • p.daemon =True,设置为守护进程,主进程执行完毕后,子进程也自动关闭。

  • p.daemon =False,设置为非守护进程,主进程等待子进程,子进程执行完毕后,主进程才结束。

import multiprocessing
import time

def task(arg):
    time.sleep(2)
    print("执行中...")

if __name__ == '__main__':
    multiprocessing.set_start_method("spawn")
    p1=multiprocessing.Process(target=task,args=('xxx',))
    p1.daemon=True
    p1.start()
    time.sleep(2)
    print("继续执行...")
#继续执行...
import multiprocessing
import time

def task(arg):
    time.sleep(2)
    print("执行中...")

if __name__ == '__main__':
    multiprocessing.set_start_method("spawn")
    p1=multiprocessing.Process(target=task,args=('xxx',))
    p1.daemon=False
    p1.start()
    time.sleep(2)
    print("继续执行...")
# 继续执行...
# 执行中...

(4)进程的名称的设置和获取

  • getpid:返回调用进程自身的进程ID。用于标识进程自身。

  • getppid:返回调用进程的父进程ID。用于标识创建调用进程的父进程。

  • multiprocessing.current_process().name:获取当前进程的名字

import multiprocessing
import os
import threading
import time

def func():
    time.sleep(3)

def task(arg):
    for i in range(10):
        t=threading.Thread(target=func)
        t.start()
    #getpid、getppid分别获取当前进程的进程ID和当前进程的父进程ID。
    print(os.getpid(),os.getppid())
    print("线程个数",len(threading.enumerate()))
    time.sleep(2)
    print("当前进程的名称:",multiprocessing.current_process().name)

if __name__ == '__main__':
    print(os.getpid())
    multiprocessing.set_start_method("spawn")
    p1=multiprocessing.Process(target=task,args=('xxx',))
    p1.name="哈哈哈哈哈"
    p1.start()
    print("继续执行...")
# 33756
# 继续执行...
# 22624 33756
# 线程个数 11
# 当前进程的名称: 哈哈哈哈哈

备注:线程计算方法   有1(执行task的线程)+ 10(循环创建的线程)= 11个线程

(5)自定义进程类,直接将线程需要做的事写到run方法中。

import multiprocessing
class MyProcess(multiprocessing.Process):
    def run(self):
        print("执行此进程",self)

if __name__ == '__main__':
    multiprocessing.set_start_method("spawn")
    p=MyProcess(args=('xxx',))
    p.start()
    print("继续执行...")
# 继续执行...
# 执行此进程 <MyProcess name='MyProcess-1' parent=29592 started>

(6)CPU个数,程序一般创建多少个进程?(利用CPU多核优势)

import multiprocessing
n=multiprocessing.cpu_count()
print(n)
#8
import multiprocessing

def task():
    pass

if __name__ == '__main__':
    count=multiprocessing.cpu_count()
    for i in range(count-1):
        p=multiprocessing.Process(target=task)
        p.start()

二. 进程间数据的共享

        进程是资源分配的最小单元,每个进程中都维护自己独立的数据,不共享

import multiprocessing
def task(data):
    data.append(666)

if __name__ == '__main__':
    data_list=[]
    p=multiprocessing.Process(target=task,args=(data_list,))
    p.start()
    p.join()
    print("主进程:",data_list)
# 主进程: []

        如果想要让他们之间进行共享,则可以借助一些特殊的东西来实现。

1.共享

        multiprocessing.Value: 这是一个类,用来创建可以在不同进程间共享的值。它允许在多进程环境中安全地共享基本数据类型,如整数、浮点数等。

        在 Python 的 multiprocessing 模块中,常见的类型代码包括 'i'(整数)、'd'(浮点数)、'c'(字符,但通常用于 Array 而非 Value)等。

from multiprocessing import Value, Process

def func(n,m1,m2):
    n.value=888
    #将字符串 'a' 使用 utf-8 编码转换成了字节串 b'a',然后赋值给 m1.value
    m1.value='a'.encode('utf-8')
    m2.value="武"

if __name__ == '__main__':
    #这里的作用是使用Value类从multiprocessing模块创建一个可以在进程间共享的整数值
    #'i': 这个字符代表了要创建的共享变量的类型。在本例中,'i' 表示这是一个整数(integer)类型。
    # 666: 这是共享变量初始化的值。即这个可以在进程间共享的整数的初始值被设定为666。
    num=Value('i',666)
    #创建了一个新的共享内存变量 v1,类型指定为 'c',这通常表示一个字符类型
    v1=Value('c')
    #试图使用 'u' 类型创建一个 multiprocessing.Value 实例。但是,按照 multiprocessing.Value 的标准用法,类型代码 'u' 并不是直接支持的。
    v2=Value('u')
    p=Process(target=func,args=(num,v1,v2))
    p.start()
    p.join()
    print(num.value)
    print(v1.value)
    print(v2.value)
# 888
# b'a'
# 武
from multiprocessing import Process, Value, Array
def f(data_array):
    data_array[0] = 666

if __name__ == '__main__':
    arr = Array('i', [11, 22, 33, 44]) # 数组:元素类型必须是int; 只能是这么几个数据。
    p = Process(target=f, args=(arr,))
    p.start()
    p.join()
    print(arr[:])
#[666, 22, 33, 44]

        利用 Python 的 multiprocessing 模块中的 Manager 类来创建一个管理器上下文。这个管理器允许您创建可在多个进程之间共享的容器,如列表、字典等。这种方式比直接使用 Value 或 Array 更灵活,尤其适合于需要共享复杂数据结构的场景。 

from multiprocessing import Process, Manager
def f(d, l):
    d[1] = '1'
    d['2'] = 2
    d[0.25] = None
    l.append(666)

if __name__ == '__main__':
    with Manager() as manager:
        d = manager.dict()
        l = manager.list()
        p = Process(target=f, args=(d, l))
        p.start()
        p.join()
        print(d)
        print(l)
# {1: '1', '2': 2, 0.25: None}
# [666]

2.交换

(1)Queues

        使用 queue = multiprocessing.Queue() 这段代码时,创建一个线程或进程安全的队列,这个队列允许您在多个进程之间安全地传递数据,用于进程间通信的一个非常实用的数据结构。

        q.put(i) 表示正向这个队列中放入一个元素 i。这里 i 应该是一个在上下文中已经定义过的变量,意味着即使有多个进程同时尝试向队列中放入或获取数据,队列也能保证数据的正确性和完整性,不会引发冲突。

        一旦数据被放入队列,其他进程可以通过 q.get() 方法来取出这个数据。这是一种典型的“生产者-消费者”模型,其中一个进程(生产者)向队列中放入数据,另一个或多个进程(消费者)从队列中取出并处理数据。

import multiprocessing
def task(q):
    for i in range(10):
        q.put(i)

if __name__ == '__main__':
    queue = multiprocessing.Queue()
    p = multiprocessing.Process(target=task, args=(queue,))
    p.start()
    p.join()
    print("主进程")
    print(queue.get())
    print(queue.get())
    print(queue.get())
    print(queue.get())
    print(queue.get())
# 主进程
# 0
# 1
# 2
# 3
# 4

(2)Pipes

import time
import multiprocessing
def task(conn):
    time.sleep(1)
    conn.send([111, 22, 33, 44])
    data = conn.recv() # 阻塞
    print("子进程接收:", data)
    time.sleep(2)

if __name__ == '__main__':
    parent_conn, child_conn = multiprocessing.Pipe()
    p = multiprocessing.Process(target=task, args=(child_conn,))
    p.start()
    info = parent_conn.recv() # 阻塞
    print("主进程接收:", info)
    parent_conn.send(666)
# 主进程接收: [111, 22, 33, 44]
# 子进程接收: 666

 3. 进程锁

如果多个进程抢占式去做某些操作时候,为了防止操作出问题,可以通过进程锁来避免。

        lock = multiprocessing.RLock() 时,您初始化了一个可重入锁(Reentrant Lock),这是 multiprocessing 模块提供的一个同步原语。可重入锁允许同一个进程多次获得同一个锁,而不会发生死锁。这对于需要在多进程中保护共享资源的情况非常有用,尤其是当某个进程可能在其持有锁的期间再次请求同一把锁时。

        在每个进程中,对于那些需要互斥访问的资源,您需要在访问之前获取锁(lock.acquire()),并在访问完毕后释放锁(lock.release())

import time
import multiprocessing

def task(lock):
    print("开始")
    lock.acquire()
    # 假设文件中保存的内容就是一个值:10
    with open('f1.txt', mode='r', encoding='utf-8') as f:
        current_num = int(f.read())
    print("排队抢票了")
    time.sleep(0.5)
    current_num -= 1

    with open('f1.txt', mode='w', encoding='utf-8') as f:
        f.write(str(current_num))
    lock.release()

if __name__ == '__main__':
    multiprocessing.set_start_method("spawn")
    lock = multiprocessing.RLock()  # 进程锁
    for i in range(10):
        p = multiprocessing.Process(target=task, args=(lock,))
        p.start()
    # spawn模式,需要特殊处理。
    time.sleep(7)
# 开始
# 排队抢票了
# 开始
# 开始
# 开始
# 开始
# 开始
# 开始
# 开始
# 开始
# 开始
# 排队抢票了
# 排队抢票了
# 排队抢票了
# 排队抢票了
# 排队抢票了
# 排队抢票了
# 排队抢票了
# 排队抢票了
# 排队抢票了

4. 进程池

注意:如果在进程池中要使用进程锁,则需要基于Manager中的Lock和RLock来实现。

        通过使用 manager = multiprocessing.Manager() 创建的管理器,您能够创建可在多个进程间共享的同步对象,如锁。因此,lock_object = manager.RLock() # Lock 正确地创建了一个可在进程池中各个进程间共享的可重入锁(RLock)。这解决了之前直接使用 multiprocessing.RLock() 时遇到的共享问题,因为 Manager 自动处理了跨进程的数据同步。

import time
import multiprocessing
from concurrent.futures.process import ProcessPoolExecutor

def task(lock):
    print("开始")
    # lock.acquire()
    # lock.relase()
    with lock:
        # 假设文件中保存的内容就是一个值:10
        with open('f1.txt', mode='r', encoding='utf-8') as f:
            current_num = int(f.read())

        print("排队抢票了")
        time.sleep(1)
        current_num -= 1

        with open('f1.txt', mode='w', encoding='utf-8') as f:
            f.write(str(current_num))

if __name__ == '__main__':
    pool = ProcessPoolExecutor()
    # lock_object = multiprocessing.RLock() # 不能使用
    manager = multiprocessing.Manager()
    lock_object = manager.RLock() # Lock
    for i in range(10):
        pool.submit(task, lock_object)
# 开始
# 排队抢票了
# 开始
# 开始
# 开始
# 开始
# 开始
# 开始
# 开始
# 排队抢票了
# 开始
# 排队抢票了
# 开始
# 排队抢票了
# 排队抢票了
# 排队抢票了
# 排队抢票了
# 排队抢票了
# 排队抢票了
# 排队抢票了

 

 

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

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

相关文章

93.游戏的启动与多开-进程枚举多开检测

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a;易道云信息技术研究院 上一个内容&#xff1a;92.游戏的启动与多开-多开检测概述 枚举多开检测在事前检测用的很少&#xff0c;在事中…

Https配置免费SSL证书

本文目录 前言一、前提1.1 服务器1.2 域名 二、Certbot简介2.1 Apache服务器2.2 Nginx服务器 三、自动更新证书四、效果 前言 HTTPS &#xff08;全称&#xff1a;Hypertext Transfer Protocol Secure &#xff09;&#xff0c;是以安全为目标的 HTTP 通道&#xff0c;在HTTP的…

【重学 MySQL】二、MySQL 介绍

【重学 MySQL】二、MySQL 介绍 MySQL 概述MySQL 的主要特点MySQL 的应用场景结论 MySQL 发展史初始创建与发布开源与快速成长重要版本发布收购与变革分支与竞争持续发展与现代应用 关于 MySQL8.0主要新特性和改进兼容性和迁移应用场景总结 为什么选择 MySQLOracle VS MySQL基本…

【Elasticsearch】Elasticsearch集群在分布式环境下的管理

文章目录 &#x1f4d1;前言一、集群规划与设计1.1 集群拓扑结构设计1.2 节点角色分配1.3 分片与副本配置 二、集群管理与运维2.1 集群监控2.2 故障处理2.3 性能优化 三、扩展与升级3.1 集群扩展3.2 集群升级3.3 灾备与容灾 &#x1f324;️总结 &#x1f4d1;前言 Elasticsear…

【重构获得模式 Refactoring to Patterns】

重构获得模式 Refactoring to Patterns 面向对象设计模式是“好的面向对象设计”&#xff0c;所谓“好的面向对象设计”指的是那些可以满足“应对变化&#xff0c;提高复用”的设计。 现代软件设计的特征是“需求的频繁变化”。设计模式的要点是“寻找变化点&#xff0c;然后…

2024.9.3 作业

自己封装 栈和队列 #include <iostream>using namespace std;class mystack { private:int *data;int size;int top; public://无参构造mystack():size(10){data new int[size];top -1;size 10;}//有参构造mystack(int s){data new int[s];top -1;size s;}//赋值my…

智慧医院是什么?建设智慧医院的关键步骤

智慧医院是什么&#xff1f; 智慧医院是一种新型的医疗机构&#xff0c;它利用先进的信息技术、数据分析和智能化系统&#xff0c;优化医院的管理和服务流程&#xff0c;提高医疗质量和效率。在智慧医院中&#xff0c;所有的运营和管理环节都可以通过数据驱动的方式来实现优化…

【网络安全】服务基础第一阶段——第十节:Windows系统管理基础---- 组策略高级应用

目录 一、组策略的基本概念 1.1 组策略的基本概念 1.1.1 组策略对象 1.2 配置 1.2.1 计算机配置&#xff08;Computer Configuration&#xff09; 1.2.2 用户配置&#xff08;User Configuration&#xff09; 1.3 作用范围 1.4 继承和优先级 1.4.1 继承&#xff08;In…

【AI】Pytorch_模型构建

建议点赞收藏关注&#xff01;持续更新至pytorch大部分内容更完。 本文已达到10w字&#xff0c;故按模块拆开&#xff0c;详见目录导航。 整体框架如下 数据及预处理 模型及其构建 损失函数及优化器 本节目录 模型线性回归逻辑回归LeNetAlexNet 构建模块组织复杂网络初始化网络…

SpringBoot学习(3)(配置文件的基本使用)

1、初步大致学习方向&#xff08;基础&#xff09; 配置文件整合MyBatisBean管理&#xff08;主要学习如何管理第三方bean对象&#xff1f;&#xff1f;如导入一个jar包&#xff0c;这个jar包中的一些对象&#xff0c;如何注入到Ioc容器里&#xff09;自动配置原理&#xff08;…

史上最全的Mysql索引教程

一、什么是索引 1.1 索引简介 索引是数据库中用来提高数据检索效率的数据结构。它类似于书籍的目录&#xff0c;可以帮助用户快速找到所需的数据&#xff0c;而不必扫描整个数据集。在数据库系统中&#xff0c;索引可以显著提高查询性能。 所谓的存储引擎&#xff0c;说白了…

【mysql】SQL语言的概述

基本select语句的使用&#xff1a; SQL概述&#xff1a; 1946年&#xff0c;第一台电脑诞生了&#xff0c;有很多基础技术在里面&#xff0c;但是在几十年来&#xff0c;保留下来的技术SQL就是其中之一&#xff0c; 1974年的时候&#xff0c;IBM的研究员发布了一篇揭开数据库…

代码随想录算法训练营第35天|背包问题基础、46. 携带研究材料(01背包二维解法)(01背包一维解法)(acm)、416. 分割等和子集

目录 0、背包问题基础01背包 46. 携带研究材料&#xff08;01背包&#xff09;1、题目描述2、思路3、code&#xff08;二维解法&#xff09;3-1、code&#xff08;一维解法&#xff09;4、复杂度分析 416. 分割等和子集1、题目描述2、思路3、code4、复杂度分析 0、背包问题基础…

如何有效地管理个人时间:策略与技巧

在快节奏的生活环境中&#xff0c;时间成为了最宝贵的资源之一。有效地管理时间不仅能提高工作效率&#xff0c;还能提升生活质量&#xff0c;使你有更多的时间投入到家庭、爱好和个人成长中去。本文将分享一些实用的时间管理技巧&#xff0c;帮助你更好地安排每日事务。 时间…

[HZNUCTF 2023 preliminary]easyAPK-快坚持不下去的第三天

第一做安卓题&#xff0c;前提jadx,java环境&#xff0c;模拟器&#xff0c;我配了好久&#xff0c; 这段代码实现了一个简单的登录界面&#xff0c;用户需要输入用户名和密码。用户名和密码会与预设的硬编码值进行比较&#xff0c;登录成功后会启动另一个 Activity。如果密码错…

TS 学习(一)

如果我们在 ts 中写 不用运行就能在文件中报错 ts 是一种静态类型的检查 能将运行时出现的错误前置 一般不用 命令行编译 ts 转换成 js 将中文转码 tsc index&#xff08;.ts&#xff09; 输入命令生成 配置文件 能在中间进行 配置转换成 js 的哪个规范 es5 还是 6 和其它转…

鸿蒙(API 12 Beta6版)图形【过度绘制调试使用指导】方舟2D图形服务

当应用页面布局的嵌套程度过深时&#xff0c;应用渲染阶段会存在一些组件的绘制指令被其他组件的绘制指令部分或完全覆盖遮挡的情况&#xff0c;造成冗余的cpu、gpu等计算资源的使用。这种一个屏幕上的像素点被重复绘制了多次的情况被称为过度绘制&#xff08;Overdraw&#xf…

Vite - 兼容旧版浏览器 plugin-legacy(2)

目录 1&#xff0c;问题2&#xff0c;解决3&#xff0c;String 其他新增 API 的版本 接上文 Vite - 兼容旧版浏览器 plugin-legacy&#xff08;1&#xff09; 1&#xff0c;问题 客户浏览器报错&#xff0c;不支持 replaceAll 方法。 该方法在 query-string 依赖内部使用了。…

通过生日计算年龄

// 获取当前月 function getDate(date) {let d new Date(date);// 将日期设置为下月一号d.setMonth(d.getMonth() 1);d.setDate(1);// 获取本月最后一天d.setDate(d.getDate() - 1);return d.getDate(); } // 获取年龄 传出生日期和当前日期&#xff0c;当前日期可以不用传 f…

双指针(1)_数组分块_移动零问题

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 双指针(1)_数组分块_移动零问题 收录于专栏【经典算法练习】 本专栏旨在分享学习C的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 1.…