🗒️Python 多进程

type
status
slug
summary
tags
category
icon
password
Date
进程是操作系统进行资源分配和调度的基本单位

创建多进程

multiprocessing模块提供了一个创建进程的类Process,创建进程有以下两种方法。
  • 创建一个Process类的实例,并指定目标任务函数。
  • 自定义一个类并继承Process类,重写其__init__()方法和run()方法。
 

Semaphore用来控制对共享资源的访问数量,可以控制同一时刻并发的进程数

 

使用锁

每一个子进程任务函数都加了锁Lock。使用锁也非常简单,首先初始化一个锁的实例lock=multiprocessing.Lock(),然后在需要独占的代码前后加锁(先获取锁),即调用lock.acquire()方法,运行完成后释放锁,即调用lock.release()方法;也可以使用上下文关键字with

Event用来实现进程之间同步通信

场景:当进程需要在某个特定条件满足后才能继续执行时
Event对象内部维护一个内部标志,可以被设置和清除

工作原理

  • Event对象有一个内部标志,初始值为False
  • set()方法用于将标志设置为True
  • clear()方法用于将标志设置为False
  • is_set()方法用于检查标志是否被设置。
  • wait()方法用于阻塞进程,直到标志被设置。
在这个例子中,wait_for_event函数会等待Event对象e的内部标志被设置。set_event函数在等待两秒后设置这个标志。两个函数分别在不同的进程中运行。
当你运行这个程序时,你会看到wait_for_event进程开始等待,直到set_event进程设置了Event对象的内部标志。一旦标志被设置,wait_for_event进程会继续执行。
这样就实现了一个简单的进程间同步机制
 

队列Queue

在单线程或单进程环境中,数据结构如列表、字典等通常足够用于数据存储和传输。但在多进程环境中,由于每个进程拥有自己独立的内存空间,直接的数据共享变得复杂和危险。这就是 Queue 出现的背景和动机
基础概念和原理
Queue 是一个先进先出(FIFO)的数据结构,它在 multiprocessing 库中有特殊的实现,以支持进程间的安全通信。这是通过底层的管道(Pipe)和锁(Lock)机制来实现的。当一个进程想要将数据放入队列时,它会首先获得一个锁,以确保在同一时刻只有一个进程可以访问队列。然后,数据会被发送到一个管道,该管道连接到队列。当另一个进程想要从队列中取出数据时,它也需要首先获得锁,然后从管道中读取数据。
Queue 通常用于以下几种场景:
  1. 任务队列:多个进程可以从队列中取出任务进行处理。
  1. 数据共享:当需要在多个进程之间共享大量数据时。
  1. 日志和监控:一个进程可以负责收集来自其他多个进程的日志或监控数据。
 
数据共享的场景中,一个进程(通常是主进程)负责生成或收集数据,然后通过队列将数据发送给其他进程进行进一步的处理或分析
 

进程池Pool

Pool通常用来并行处理多个独立任务或数据集合。Pool的出现主要是为了简化这种并行处理,让程序员能够更容易地实现多进程编程而不必深入到进程管理的细节
工作原理
Pool 类内部维护了一个进程队列和一个任务队列。当你提交一个任务(通常是一个函数调用)给 Pool,它会将该任务放入任务队列。然后,Pool 会从进程队列中选取一个可用的进程来执行这个任务。一旦任务完成,结果会被存储,并且该进程会被返回到进程队列中,以便用于后续的任务。
常用方法
  • Pool.map(func, iterable): 将 iterable 中的每个元素应用于函数 func,并返回一个包含所有结果的列表。
  • Pool.apply(func, args): 使用参数 args 调用函数 func,并返回结果。
  • Pool.apply_async(func, args): 异步版本的 apply,返回一个 AsyncResult 对象。
  • Pool.close(): 关闭进程池,停止接受新的任务。
  • Pool.join(): 等待所有进程完成。
使用 map 方法
使用 applyapply_async 方法
 
如果没有使用with语句,而是直接创建了Pool对象,需要close手动关闭进程池并join等待所有进程完成
 
数据交换Pipe
Pipe 允许两个进程通过一个双向或单向的通道进行数据传输
工作原理
当创建一个 Pipe 时,实际上是在操作系统级别创建了一个管道。这个管道有两个端点,每个端点都是一个连接对象。你可以通过这些连接对象的 sendrecv 方法来发送和接收数据。
这个例子中,主进程和工作进程通过 Pipe 的两个端点(parent_connchild_conn)进行通信。工作进程通过 child_conn.send() 发送消息,主进程通过 parent_conn.recv() 接收消息
Pipe典型用例
  1. 任务分发:一个主进程可以通过 Pipe 将任务分发给多个工作进程。
  1. 数据聚合:多个工作进程可以通过 Pipe 将处理结果发送回主进程。
  1. 流式处理:在数据流处理的场景中,多个进程可以通过 Pipe 进行数据链路。
 
Loading...

© NotionNext 2021-2025