Python多进程并发与同步机制超详细讲解

目录
  • 多进程
    • 僵尸进程
    • Process类
    • 函数方式
    • 继承方式
  • 同步机制
  • 状态管理Managers

在《多线程与同步》中介绍了多线程及存在的问题,而通过使用多进程而非线程可有效地绕过全局解释器锁。 因此,通过multiprocessing模块可充分地利用多核CPU的资源。

多进程

多进程是通过multiprocessing包来实现的,multiprocessing.Process对象(和多线程的threading.Thread类似)用来创建一个进程对象:

  • 在类UNIX平台上,需要对每个Process对象调用join()方法 (实际上等同于wait)避免其成为僵尸进程。
  • multiprocessing提供了threading包中没有的IPC(比如Pipe和Queue),效率上更高。应优先考虑Pipe和Queue,避免使用Lock/Event/Semaphore/Condition等同步方式。
  • 多进程应尽量避免共享资源。必要时可以通过共享内存和Manager的方法来共享资源。

僵尸进程

在unix或unix-like系统中,当一个子进程退出后,它就会变成一个僵尸进程,如果父进程没有通过wait系统调用来读取这个子进程的退出状态的话,这个子进程就会一直维持僵尸进程状态(占据部分系统资源,无法释放)。

要清除僵尸进程,有:

结束父进程(一般是主进程):当父进程退出的时候僵尸进程也会被随之清除。

读取子进程退出状态:如通过multiprocessing.Process产出的进程可以:

  • 调用join()来等待子进程的方法来(内部会wait子进程);
  • 在父进程中处理SIGCHLD信号:在处理程序中调用wait系统调用或者直接设置为SIG_IGN来清除僵尸进程;

把进程变成孤儿进程,这样进程就会自动交由init进程来自动处理。

通过设定signal.signal(signal.SIGCHLD, signal.SIG_IGN)或join进程可避免僵尸进程的产生

def zombieProc():
    print("zombie running")
    time.sleep(5)
    print("zombie exit")
if __name__ == '__main__':
    signal.signal(signal.SIGCHLD, signal.SIG_IGN)
    proc = multiprocessing.Process(target=zombieProc)
    proc.start()
    # proc.join()
    time.sleep(30)

Process类

Process([group [, target [, name [, args [, kwargs]]]]]),实例化得到的对象,表示一个子进程任务:

  • group参数未使用,值始终为None;
  • target表示调用对象,即子进程要执行的任务;
  • args表示调用对象的位置参数元组,args=(1, ‘test’, [‘one’]);
  • kwargs表示调用对象的字典参数,kwargs={‘name’:‘mike’,‘age’:18};
  • name为子进程的名称;

Process类的属性与方法:

  • start():启动进程,并执行其run方法;
  • run():进程启动时运行的方法,继承Process类时必须要实现方法;
  • terminate():强制终止进程,不会进行任何清理操作(若p创建了子进程,则子进程就成了僵尸进程);如进程还持有锁等,那么也不会被释放,进而导致死锁;
  • is_alive():返回进程是否在运行状态;
  • join([timeout]):等待进程终止;
  • daemon:默认值为False,如果设为True,代表为守护进程(当父进程终止时,随之终止;并且不能创建自己的新进程),必须在start()之前设置;
  • name:进程的名称;
  • pid/ident:进程的pid;
  • exitcode:进程在运行时为None、如果为–N,表示被信号N结束;
  • authkey:进程的身份验证码(默认是由os.urandom()随机生成的32字符的字符串),在涉及网络连接的底层进程间通信时提供安全性;

也可通过os.getpid()获取进程的PID,os.getppid()获取父进程的PID。

函数方式

通过Process类直接运行函数:

def simpleRoutine(name, delay):
    print(f"routine {name} starting...")
    time.sleep(delay)
    print(f"routine {name} finished")
if __name__ == '__main__':
    thrOne = multiprocessing.Process(target=simpleRoutine, args=("First", 1))
    thrTwo = multiprocessing.Process(target=simpleRoutine, args=("Two", 2))
    thrOne.start()
    thrTwo.start()
    thrOne.join()
    thrTwo.join()

继承方式

通过继承Process类,并实现run方法来启动进程:

class SimpleProcess(multiprocessing.Process):
    def __init__(self, name, delay):
        super().__init__()
        self.name = name
        self.delay = delay
    def run(self):
        print(f"Process {self.name} starting...")
        time.sleep(self.delay)
        print(f"Process {self.name} finished")
if __name__ == '__main__':
    thrOne = SimpleProcess("First", 2)
    thrTwo = SimpleProcess("Second", 1)
    thrOne.start()
    thrTwo.start()
    thrOne.join()
    thrTwo.join()

同步机制

进程间同步与线程间同步类似(只是所有对象都在multiprocessing模块中):

  • Lock/Rlock: 通过acquire()和release()来获取与释放锁;
  • Event: 事件信号,通过set()和clear()来设定与清楚信号;通过wait()来等待信号;
  • Condition: 条件变量;通过wait()用来等待条件,通过notify/notify_all()来通知等待此条件的进程(等待与通知前,都需先持有锁);
  • Semaphore: 信号量;维护一个计数器;
  • Barrier: 屏障;只有等待进程数量达到要求数量,才会同时开始执行屏障保护后的代码。

屏障示例:

def waitBarrier(name, barr: multiprocessing.Barrier):
    print(f"{name} waiting for open")
    try:
        barr.wait()
        print(f"{name} running")
        time.sleep(2)
    except multiprocessing.BrokenBarrierError:
        print(f"{name} exception")
    print(f"{name} finished")
def openFun():  # 屏障满足条件时,执行一次
    print("barrier opened")
if __name__ == '__main__':
    signal = multiprocessing.Barrier(5, openFun)
    for i in range(10):
        multiprocessing.Process(target=waitBarrier, args=(i, signal)).start()
        time.sleep(1)

当第5个进程启动时,前面5个进程会同时开始执行(openFun函数会执行一次);当第10个进程启动时,后面5个进程会同时开始执行一次(openFun函数又会执行一次)。

状态管理Managers

Managers提供了一种创建由多进程(包括跨机器间进程共享)共享的数据的方式:

  • multiprocessing.Manager()返回一个SyncManager对象;此对象对应着一个管理者子进程(manager process)以及代理(其他子进程使用);
  • 它确保当某一进程修改了共享对象之后,其他进程中的共享对象也会得到更新;
  • 其支持的类型有:list、dict、Namespace、Lock、RLock、Semaphore、BoundedSemaphore、Condition、Event、Queue、Value和Array。

多进程进共享字典与列表(每个进程中都能看到其他进程修改过的内容)

def worker(dictContext: dict, lstContext: list, name):
    pid = os.getpid()
    dictContext[name] = pid
    lstContext.append(pid)
    print(f"{name} worker: {lstContext}")
def managerContext():
    mgr = multiprocessing.Manager()
    multiprocessing.managers
    dictContext = mgr.dict()
    lstContext = mgr.list()
    jobs = [multiprocessing.Process(target=worker, args=(dictContext, lstContext, i)) for i in range(10)]
    for j in jobs:
        j.start()
    for j in jobs:
        j.join()
    print('Results:', dictContext)

到此这篇关于Python多进程并发与同步机制超详细讲解的文章就介绍到这了,更多相关Python多进程并发内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • python多进程登录远端服务器

    目录 通过Semaphore 来控制对共享资源的的访问数量,可以控制同一时刻并发的进程数 . #/usr/bin/python # _*_ coding: utf-8 _*_ import multiprocessing import time import paramiko def ssh(s,i,host): try: s.acquire() print(time.strftime('%H:%M:%S'),multiprocessing.current_process().name + "

  • Python多进程之进程同步及通信详解

    目录 进程同步 Lock(锁) 进程通信 Queue(队列) Pipe(管道) Semaphore(信号量) Event(事件) 总结 上篇文章介绍了什么是进程.进程与程序的关系.进程的创建与使用.创建进程池等,接下来就来介绍一下进程同步及进程通信. 进程同步 当多个进程使用同一份数据资源的时候,因为进程的运行没有顺序,运行起来也无法控制,如果不加以干预,往往会引发数据安全或顺序混乱的问题,所以要在多个进程读写共享数据资源的时候加以适当的策略,来保证数据的一致性问题. Lock(锁) 一个Loc

  • python多进程和多线程介绍

    目录 一.什么是进程和线程 二.多进程和多线程 三.python中的多进程和多线程 1.多进程 2.多线程 一.什么是进程和线程 进程是分配资源的最小单位,线程是系统调度的最小单位. 当应用程序运行时最少会开启一个进程,此时计算机会为这个进程开辟独立的内存空间,不同的进程享有不同的空间,而一个CPU在同一时刻只能够运行一个进程,其他进程处于等待状态. 一个进程内部包括一个或者多个线程,这些线程共享此进程的内存空间与资源.相当于把一个任务又细分成若干个子任务,每个线程对应一个子任务. 二.多进程和

  • 深入解析Python中的多进程

    目录 前言 1.创建进程 2.多进程中的Queue 3.多进程与多线程的性能比较 4.进程池pool 5.共享内存 6.进程锁lock 前言 现在我们的计算机都是多个核的,通俗来说就是多个处理或者计算单元.为了加快运算和处理速度,我们可以将不同的任务交给多个核心进行同时处理,从而提高了运算速度和效率,多个核心同时运作就是多个进程同时进行,这就是多进程. 1.创建进程 创建进程和创建线程的方法基本一致,请看下面代码: # coding:utf-8 # 导入多进程的包,并重命名为mp import

  • python 多线程与多进程效率测试

    目录 1.概述 2.代码练习 3.运行结果 1.概述 在Python中,计算密集型任务适用于多进程,IO密集型任务适用于多线程 正常来讲,多线程要比多进程效率更高,因为进程间的切换需要的资源和开销更大,而线程相对更小,但是我们使用的Python大多数的解释器是Cpython,众所周知Cpython有个GIL锁,导致执行计算密集型任务时多线程实际只能是单线程,而且由于线程之间切换的开销导致多线程往往比实际的单线程还要慢,所以在 python 中计算密集型任务通常使用多进程,因为各个进程有各自独立的

  • 一篇文章带你搞定Python多进程

    目录 1.Python多进程模块 2.Python多进程实现方法一 3.Python多进程实现方法二 4.Python多线程的通信 5.进程池 1.Python多进程模块 Python中的多进程是通过multiprocessing包来实现的,和多线程的threading.Thread差不多,它可以利用multiprocessing.Process对象来创建一个进程对象.这个进程对象的方法和线程对象的方法差不多也有start(), run(), join()等方法,其中有一个方法不同Thread线

  • python中的多进程的创建与启动方式

    目录 一.多进程的创建:多进程的创建方法有两种: 1.通过Process创建多进程 Process语法结构: 2.通过进程池创建并启动多进程 3.通过继承的方法创建多进程 4.进程创建与启动完整代码 python中的并发有三种形式,多进程.多线程.协程.执⾏并发任务的⽬的是为了提⾼程序运⾏的效率. 一.多进程的创建:多进程的创建方法有两种: 1.通过Process创建多进程 Process语法结构: Process(group, target, name, args, kwargs) group

  • python多进程及通信实现异步任务的方法

    目录 一.python多进程及通信基本用法 1.多进程的基本实现 a.Process重写run方法 b.使用Process和target方法 c.直接使用Process类 2.多进程的通信 a.Queue b.Pipe 二.python多进程实战 1.使用进程池快速抽取数据 2.多进程及通信完成数据清洗和保存 3.多进程及通信实现异步任务需求 写在最前面,说实话python多进程这块儿知识对于很少使用python多进程或者没有实际使用过多python进程解决问题的人来说,还是有一定难度的.本人也

  • Python多进程并发与同步机制超详细讲解

    目录 多进程 僵尸进程 Process类 函数方式 继承方式 同步机制 状态管理Managers 在<多线程与同步>中介绍了多线程及存在的问题,而通过使用多进程而非线程可有效地绕过全局解释器锁. 因此,通过multiprocessing模块可充分地利用多核CPU的资源. 多进程 多进程是通过multiprocessing包来实现的,multiprocessing.Process对象(和多线程的threading.Thread类似)用来创建一个进程对象: 在类UNIX平台上,需要对每个Proce

  • React渲染机制超详细讲解

    目录 准备工作 render阶段 workloopSync beginWork completeWork commit阶段 commitWork mutation之前 mutation fiber树切换 layout layout之后 总结 准备工作 为了方便讲解,假设我们有下面这样一段代码: function App(){ const [count, setCount] = useState(0) useEffect(() => { setCount(1) }, []) const handl

  • MyBatis插件机制超详细讲解

    目录 MyBatis的插件机制 InterceptorChain MyBatis中的Plugin MyBatis插件开发 总结 MyBatis的插件机制 MyBatis 允许在已映射语句执行过程中的某一点进行拦截调用.默认情况下,MyBatis 允许使用插件来拦截的方法调用包括: Executor(update, query, flushStatements, commit, rollback, getTransaction, close, isClosed) ParameterHandler(

  • React运行机制超详细讲解

    目录 适合人群 写源码之前的必备知识点 JSX 虚拟Dom 原理简介 手写react过程 基本架子的搭建 React的源码 ReactDom.render ReactDom.Component 简单源码 适合人群 本文适合0.5~3年的react开发人员的进阶. 讲讲废话: react的源码,的确是比vue的难度要深一些,本文也是针对初中级,本意了解整个react的执行过程. 写源码之前的必备知识点 JSX 首先我们需要了解什么是JSX. 网络大神的解释:React 使用 JSX 来替代常规的

  • JavaGUI事件监听机制超详细讲解

    1.一个事件模型中有上对象:事件源,事件以及监听程序 2.事件监听机制: 事件源        事件发生的地方 事件            要发生的事情 事件处理     针对发生的事情做出的处理方案 事件监听     把事件源和事件关联起来 使用步骤: 新建一个组件(如 JButton) 将该组件添加到相应的面板(如 JFrame) 注册监听器以监听事件源产生的事件(如通过ActionListener来响应用户点击按钮) 定义处理事件的方法(如在ActionListener中的actionPe

  • Python超详细讲解内存管理机制

    目录 什么是内存管理机制 一.引用计数机制 二.数据池和缓存 什么是内存管理机制 python中创建的对象的时候,首先会去申请内存地址,然后对对象进行初始化,所有对象都会维护在一 个叫做refchain的双向循环链表中,每个数据都保存如下信息: 1. 链表中数据前后数据的指针 2. 数据的类型 3. 数据值 4. 数据的引用计数 5. 数据的长度(list,dict..) 一.引用计数机制 引用计数增加: 1.1 对象被创建 1.2 对象被别的变量引用(另外起了个名字) 1.3 对象被作为元素,

  • Python进程间通讯与进程池超详细讲解

    目录 进程间通讯 队列Queue 管道Pipe 进程池Pool 在<多进程并发与同步>中介绍了进程创建与信息共享,除此之外python还提供了更方便的进程间通讯方式. 进程间通讯 multiprocessing中提供了Pipe(一对一)和Queue(多对多)用于进程间通讯. 队列Queue 队列是一个可用于进程间共享的Queue(内部使用pipe与锁),其接口与普通队列类似: put(obj[, block[, timeout]]):插入数据到队列(默认阻塞,且没有超时时间): 若设定了超时且

  • Python多进程并发与多线程并发编程实例总结

    本文实例总结了Python多进程并发与多线程并发.分享给大家供大家参考,具体如下: 这里对python支持的几种并发方式进行简单的总结. Python支持的并发分为多线程并发与多进程并发(异步IO本文不涉及).概念上来说,多进程并发即运行多个独立的程序,优势在于并发处理的任务都由操作系统管理,不足之处在于程序与各进程之间的通信和数据共享不方便:多线程并发则由程序员管理并发处理的任务,这种并发方式可以方便地在线程间共享数据(前提是不能互斥).Python对多线程和多进程的支持都比一般编程语言更高级

  • Python 多进程并发操作中进程池Pool的实例

    在利用Python进行系统管理的时候,特别是同时操作多个文件目录,或者远程控制多台主机,并行操作可以节约大量的时间.当被操作对象数目不大时,可以直接利用multiprocessing中的Process动态成生多个进程,10几个还好,但如果是上百个,上千个目标,手动的去限制进程数量却又太过繁琐,这时候进程池Pool发挥作用的时候就到了. Pool可以提供指定数量的进程,供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求:但如果池中的进程数已经达到规定

  • 理论讲解python多进程并发编程

    一.什么是进程 进程:正在进行的一个过程或者说一个任务.而负责执行任务则是cpu. 二.进程与程序的区别 程序:仅仅是一堆代 进程:是指打开程序运行的过程 三.并发与并行 并发与并行是指cpu运行多个程序的方式 不管是并行与并发,在用户看起来都是'同时'运行的,他们都只是一个任务而已,正在干活的是cpu,而一个cpu只能执行一个任务. 并行就相当于有好多台设备,可以同时供好多人使用. 而并发就相当于只有一台设备,供几个人轮流用,每个人用一会就换另一个人. 所以只有多个cpu才能实现并行,而一个c

随机推荐