【python中的多进程了解一下?】

news2024/9/21 2:39:26

在这里插入图片描述

基本说明

多进程是指在同一台计算机中同时运行多个独立的进程。每个进程都有自己的地址空间,可用于执行一些特定的任务。这些进程可以同时执行,从而提高了程序的性能和效率。多进程可以在多核计算机上实现真正的并行计算,可以同时运行多个程序,从而大大提高了计算机的利用率。

在多进程编程中,进程之间是独立的,它们各自运行自己的程序,有自己的地址空间和系统资源,不会相互干扰。每个进程都有自己的PID(进程标识符),它是一个唯一的标识符,用于在系统中识别该进程。多进程可以通过IPC(进程间通信)来实现数据共享和通信。

Python的多进程模块multiprocessing提供了一种方便的方法来创建和管理多个进程。它可以在单个Python解释器中创建多个进程,从而实现并行计算。multiprocessing模块还提供了一些方便的功能,如进程池、进程通信和共享内存等。

多进程编程可以在很多场景中提高程序的运行效率,如CPU密集型任务、I/O密集型任务、并行计算、大规模数据处理和机器学习等。但需要注意多进程之间的数据同步和通信,以避免数据竞争和死锁等问题。

import multiprocessing
from PIL import Image, ImageFilter

def process_image(filename, size, q):
    """使用高斯模糊对图像进行处理"""
    img = Image.open(filename)
    img = img.resize(size)
    img = img.filter(ImageFilter.GaussianBlur(radius=5))
    q.put(img)

if __name__ == '__main__':
    filenames = ["image1.jpg", "image2.jpg", "image3.jpg"]
    size = (800, 800)
    q = multiprocessing.Queue()
    processes = []
    for filename in filenames:
        p = multiprocessing.Process(target=process_image, args=(filename, size, q))
        processes.append(p)
        p.start()
    for p in processes:
        p.join()
    images = []
    while not q.empty():
        images.append(q.get())
    for i, img in enumerate(images):
        img.save(f"processed_image_{i}.jpg")

这个程序使用多进程对多个图像进行处理。它将每个图像分配给一个进程来进行处理,并使用队列将处理后的图像收集起来。在这个例子中,我们对每个图像进行了大小调整和高斯模糊,然后将它们保存在磁盘上。

import multiprocessing
import requests
from bs4 import BeautifulSoup

def scrape_page(url, q):
    """从网页中提取信息"""
    r = requests.get(url)
    soup = BeautifulSoup(r.content, 'html.parser')
    title = soup.title.string
    q.put((url, title))

if __name__ == '__main__':
    urls = ["http://www.example.com", "http://www.example.org", "http://www.example.net"]
    q = multiprocessing.Queue()
    processes = []
    for url in urls:
        p = multiprocessing.Process(target=scrape_page, args=(url, q))
        processes.append(p)
        p.start()
    for p in processes:
        p.join()
    results = []
    while not q.empty():
        results.append(q.get())
        for url, title in results:
       		print(f"{url}: {title}")

这个程序使用多进程来爬取多个网页的标题。它将每个URL分配给一个进程来处理,并使用队列将提取的标题收集起来。在这个例子中,我们使用requestsBeautifulSoup库来获取和解析网页。

进程间通信

Python的多进程模块multiprocessing提供了多种进程间通信的方式,包括:

  1. 队列(Queue):队列是最常用的进程间通信方式之一,它是线程安全的,可以在多个进程之间共享数据。可以使用multiprocessing.Queue类来创建一个队列,进程之间可以使用put()get()方法向队列中添加和获取数据。

    import multiprocessing
    
    def producer(q):
        for i in range(5):
            q.put(i)
        q.put(None)
    
    def consumer(q):
        while True:
            item = q.get()
            if item is None:
                break
            print(f"Consumed {item}")
    
    if __name__ == '__main__':
        q = multiprocessing.Queue()
        p1 = multiprocessing.Process(target=producer, args=(q,))
        p2 = multiprocessing.Process(target=consumer, args=(q,))
        p1.start()
        p2.start()
        p1.join()
        p2.join()
    

    需要注意的是,在队列中添加一个特殊的值(如None)可以用来表示队列的结束。在这个示例中,生产者进程在添加完所有数据后,向队列中添加了一个None,表示队列已经结束。消费者进程在获取到None时,就知道队列已经结束,可以退出循环。

  2. 管道(Pipe):管道是另一种进程间通信方式,它可以在两个进程之间传递数据。可以使用multiprocessing.Pipe()函数创建一个管道,它返回两个连接对象,每个连接对象可以用于向另一个进程发送数据。

    import multiprocessing
    
    def send_data(conn):
        data = [1, 2, 3, 4, 5]
        conn.send(data)
        conn.close()
    
    def receive_data(conn):
        data = conn.recv()
        print(f"Received data: {data}")
        conn.close()
    
    if __name__ == '__main__':
        parent_conn, child_conn = multiprocessing.Pipe()
        p1 = multiprocessing.Process(target=send_data, args=(child_conn,))
        p2 = multiprocessing.Process(target=receive_data, args=(parent_conn,))
        p1.start()
        p2.start()
        p1.join()
        p2.join()
    

    在这个示例中,我们创建了两个进程,一个发送进程和一个接收进程。发送进程向管道中发送一些数据,接收进程从管道中接收数据并进行处理。

    在这个示例中,我们使用multiprocessing.Pipe()函数创建了一个管道,并将其分别传递给发送进程和接收进程。发送进程使用send()方法将数据发送到管道中,接收进程使用recv()方法从管道中接收数据。

    需要注意的是,管道是双向的,每个管道有两个连接对象,分别表示管道的两端。在这个示例中,我们使用multiprocessing.Pipe()函数创建了一个管道,并将其分别传递给发送进程和接收进程。管道的两个连接对象都可以用于发送和接收数据。

    在实际应用中,管道通常被用来进行进程之间的数据传递和协调,例如,我们可以将一个大型任务拆分成多个小任务,并将这些小任务分配给多个进程来处理。在处理完成后,这些进程可以使用管道来将结果传递给主进程,主进程可以将这些结果合并并进行汇总。

    需要注意的是,管道通常比队列更快,但它只适用于两个进程之间的通信。如果需要进行多个进程之间的通信,应该使用队列或其他进程间通信方式。

  3. 共享内存(Value和Array):共享内存是一种特殊的进程间通信方式,它可以在多个进程之间共享数据。multiprocessing模块提供了ValueArray类来实现共享内存,Value用于存储单个值,Array用于存储多个值。

    import multiprocessing
    
    def modify_value(val, lock):
        with lock:
            val.value += 1
    
    def modify_array(arr, lock):
        with lock:
            for i in range(len(arr)):
                arr[i] *= 2
    
    if __name__ == '__main__':
        val = multiprocessing.Value('i', 0)
        arr = multiprocessing.Array('i', [1, 2, 3, 4, 5])
        lock = multiprocessing.Lock()
    
        p1 = multiprocessing.Process(target=modify_value, args=(val, lock))
        p2 = multiprocessing.Process(target=modify_array, args=(arr, lock))
        p1.start()
        p2.start()
        p1.join()
        p2.join()
    
        print(f"Value: {val.value}")
        print(f"Array: {arr[:]}")
    
    

    在这个示例中,我们创建了一个共享整数对象、一个共享数组对象和一个锁对象。在进程修改共享内存对象的值时,我们使用了with lock:语句来获取锁对象,以保证对共享内存对象的访问的同步和互斥。在修改完成后,锁会自动释放,以便其他进程可以继续访问共享内存对象。

    需要注意的是,在使用锁时,要尽可能地减小锁的粒度,避免出现死锁或性能问题。在实际应用中,共享内存通常被用来存储一些常用的数据,例如,程序配置信息、缓存数据等。共享内存通常比其他进程间通信方式更快,但由于数据共享的原因,也更容易出现问题。

  4. 锁(Lock):在多个进程之间共享数据时,需要使用锁来防止数据竞争。可以使用multiprocessing.Lock类来创建一个锁对象,进程可以使用acquire()release()方法来获取和释放锁。

    import multiprocessing
    
    def increment_counter(counter, lock):
        for i in range(1000):
            with lock:
                counter.value += 1
    
    if __name__ == '__main__':
        counter = multiprocessing.Value('i', 0)
        lock = multiprocessing.Lock()
    
        processes = []
        for i in range(5):
            p = multiprocessing.Process(target=increment_counter, args=(counter, lock))
            processes.append(p)
            p.start()
    
        for p in processes:
            p.join()
    
        print(f"Counter value: {counter.value}")
    
    

    在这个示例中,我们创建了一个共享整数对象counter和一个锁对象lock。进程可以使用with lock:语句来获取锁对象,以保证对共享内存对象的访问的同步和互斥。在修改完成后,锁会自动释放,以便其他进程可以继续访问共享内存对象。

    在这个示例中,我们创建了5个进程,并将它们添加到进程列表中。每个进程都会执行increment_counter()函数,该函数使用with lock:语句获取锁对象,并将共享整数对象counter加1。在执行完成后,锁会自动释放。

    需要注意的是,在使用锁时,要尽可能地减小锁的粒度,避免出现死锁或性能问题。在实际应用中,锁通常被用来保护共享数据的读写操作,以避免数据竞争和死锁等问题。

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

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

相关文章

资本观望,大厂入局,海外大模型血脉压制……国内AIGC创业者的机会在哪里?...

图片来源:由无界 AI生成 A股AI概念股直线式拉涨,技术大牛带资进组分分钟成数十亿人民币独角兽,互联网巨头争抢着入局,政府各类扶持政策持续出台,媒体动不动就是万亿风口,500万年薪难招AIGC大牛……2022年以…

57、Yolov8-seg实例分割部署MNN、OpenVINO、OAK,RK3588平台上

基本思想:部署yolov8-seg到mnn、openvino、oak平台上,仅仅做记录 实验模型:链接: https://pan.baidu.com/s/1ilX1YMuhONkisKuGuiqvWw?pwd75ti 提取码: 75ti 一、是用官方模型转onnx首先,然后进行sim一下,是用模型日期2023-04-2…

从120s到2.5s,看看人家的MyBatis批量插入数据优化,那叫一个优雅

最近在压测一批接口,发现接口处理速度慢的有点超出预期,感觉很奇怪,后面定位发现是数据库批量保存这块很慢。 这个项目用的是 mybatis-plus,批量保存直接用的是 mybatis-plus 提供的 saveBatch。 我点进去看了下源码&#xff0c…

入职华为外包一个月后,我离职向“北上广深”流浪了...

这次来聊一个大家可能也比较关心的问题,那就是就业城市选择的问题。而谈到这个问题,就不可避免地会谈到一些关于:机会?技术氛围?跳槽?薪资水平?等等一系列问题。 正好,这也是大家所…

【react全家桶】react-router

本人大二学生一枚&#xff0c;热爱前端&#xff0c;欢迎来交流学习哦&#xff0c;一起来学习吧。 <专栏推荐> &#x1f525;&#xff1a;js专栏 &#x1f525;&#xff1a;vue专栏 &#x1f525;&#xff1a;react专栏 文章目录 11 【react-router】1.准备1.1 SPA1.2 …

搞懂分布式RPC开源框架-gRPC

搞懂分布式RPC开源框架-gRPC rpc解决了什么问题&#xff0c;与消息队列应用场景比较 rpc(远程调用方法):请求回应 socket网络问题 ------> 消除端到端交互问题 业务场景&#xff1a; rpc&#xff1a;同步地处理 消息队列&#xff1a;不紧迫的非必要的 异步解决问题 &#x…

【回眸】又是一年毕业季,怎么利用ChatGPT 4.0 优化毕业论文?

目录 【回眸】又是一年毕业季&#xff0c;怎么利用ChatGPT 4.0 优化毕业论文&#xff1f; 前言 ChatGPT4.0降重提示词&#xff08;3.5表现略逊色一些&#xff0c;不过也可以用这个来作为提示词&#xff09; 举个例子 降重前的原文 构思提示词 确定提问词 选用合适的翻译…

CloudCompare如何进行二次开发?

文章目录 0.引言1.界面设计2.功能实现3.结果展示 0.引言 CloudCompare源代码编译成功后&#xff0c;即可进行二次开发&#xff0c;可以通过修改源码或者制作插件&#xff08;插件开发详见&#xff1a;CloudCompare如何进行二次开发之插件开发&#xff1f;&#xff09;实现二次开…

SpringBoot配置文件(properties与yml详解)

目录 一&#xff0c;SpringBoot配置文件 1&#xff0c;配置文件的作用 2&#xff0c;配置文件的格式 二&#xff0c;properties 配置文件说明 1&#xff0c;properties 基本语法 2&#xff0c;读取配置文件 3&#xff0c;properties 的缺点 三&#xff0c;yml配置文件说…

掌握Linux指令和权限:一个入门教程

目录 一.Linux基本指令1.ls指令2.pwd指令3.cd指令4.touch指令5.mkair指令6.rmdir和rm指令 一.Linux基本指令 1.ls指令 语法格式:ls [选项][目录或者文件] 功能&#xff1a;对于目录&#xff0c;该命令列出该目录下的所有子目录与文件。对于文件&#xff0c;将列出文件名以及其…

Chrome扩展开发指南

前言 Chrome 扩展&#xff08;通常也叫插件&#xff09;也是软件程序&#xff0c;使用 Web&#xff08;HTML, CSS, and JavaScript&#xff09;技术栈开发。允许用户自定义 Chrome 浏览体验。开发者可以通过增加特效或功能来优化体验。例如&#xff1a;效率工具、信息聚合等等。…

数据结构考研版——KMP算法

一、 我们先看下面这个算法当比较到不匹配的时候 模式串后移一位&#xff0c;并且让比较指针回去&#xff0c;这就叫做指针的回溯&#xff0c;回溯就是造成这个简单算法效率比较低的原因 这种是朴素模式匹配算法&#xff0c;时间复杂度比较高 int index(Str str,Str substr…

MAVEN安装与配置

文章目录 一、安装MAVEN二、在IDEA中进行配置 一、安装MAVEN 打开MAVEN官网下载&#xff1a;https://maven.apache.org/download.cgi 选择这两个进行下载&#xff0c;然后直接解压缩到指定的安装目录即可。 配置环境变量 1&#xff09;MAVEN_HOME设置为maven的安装目录 2&…

指令段间及文件间参数调用过程(64位 Intel架构)

指令段间及文件间参数调用过程&#xff08;64位 Intel架构&#xff09; 文章目录 指令段间及文件间参数调用过程&#xff08;64位 Intel架构&#xff09;一. 指令段间的参数调用过程1.1 推论1.2 验证 二. 文件间的参数调用过程2.1 推论2.2 验证 三. 指令解释相关补充 一. 指令段…

基于html+css的图片展示24

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

docker安装rocketMQ

1、安装jkd1.8 docker pull java:8 或者 docker pull openjdk:8 查看已安装的镜像&#xff1a; docker images 运行jdk命令 docker run -d -it --name java-8 java:8 进入JDK 容器 docker exec -it java-8 /bin/bash 查看java版本&#xff0c;进入java-8容器后输入 &#x…

金融数字新型基础设施创新开放联合体今日成立

4月18日&#xff0c;“金融数字新型基础设施创新开放联合体”&#xff08;以下简称&#xff1a;联合体&#xff09;在上海成立。联合体由上海银行、复旦大学金融科技研究院、中电金信共同发起&#xff0c;首批成员单位汇聚产业链与供给侧的中坚力量&#xff1a;国泰君安证券、太…

基于 BaiduAI 的人脸检测系统(PyQt5图形化界面实现)

文章目录 写在前面的话总体结构学生端教师端教务处系统 总结 写在前面的话 前几天有个小伙伴私我会不会做关于人脸检测与识别的小项目&#xff0c;奈何我现在主要是学习研究NLP了&#xff0c;所以关于CV的很多东西也有点力不从心&#xff0c;突然想起来去年我的毕业设计就是做…

【Vue】学习笔记-内置指令/自定义指令

内置指令 自定义指令 内置指令v-text 指令v-html指令v-cloak指令v-once指令v-pre指令 自定义指令 内置指令 我们学过的指令&#xff1a; v-bind : 单向绑定解析表达式, 可简写为 :xxx v-model : 双向数据绑定 v-for : 遍历数组/对象/字符串 v-on : 绑定事件监听, 可简写为 v…

遍历思路与子问题思路:详解二叉树的基本操作

二叉树的结构定义&#xff1a; public class BinaryTree {//内部类 表示一个结点static class TreeNode {TreeNode left; //左子树TreeNode right; //右子树char value; //结点值TreeNode(char value) {this.value value;}}public TreeNode root; //根节点... } …