multiprocessing模块

进程对象

  • 创建

    • p = Process(target=foo, args=(param,))
  • 属性

    • p.daemon: True为守护进程, 守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes are not allowed to have children, 父进程结束则自己也立刻结束; False则为非守护进程, 自身进程运行与父进程是否结束无关; p.daemon = True | False 必须在p.start()之前调用
    • p.name: 进程名
    • p.pid: 进程pid; 如果当前进程为父进程, 则p.pid与os.getpid()的结果一样
    • p.exitcode: 为None表示进程正在运行, 为-n表示由于某一个信号结束了
    • p.start(): 启动一个进程, 内部会调用p.run()方法
    • p.join(): 调用p.join()语句的进程需要等待p进程结束才能继续执行, p.join()中会调用wait函数
    • p.terminate(): 强制终止p进程, 但是不会立即终止, 所以如果在p.terminate()后紧接着是p.is_alive()则返回True, 但是如果紧接着会后面再来一个p.is_alive()就会返回False了, 第一个p.is_alive()会催促p结束
    • p.is_alive(): p进程是否还在运行
  • 僵尸进程与进程

    • 僵尸进程

      • 父进程还在执行, 但是子进程结束了, 父进程没有调用wait或者waitpid函数回收子进程的资源导致子进程死亡了但是仍然占用着进程资源
      • 对系统有害, 会造成资源浪费
        • 解决

          1. 如果已经产生了僵尸进程: 杀掉父进程, 让子进程成为孤儿进程从而交给init进程管理即可
          2. 预防僵尸进程: p为进程对象, 父进程p调用join()方法
    • 孤儿进程

      • 父进程结束, 但是子进程还在执行
      • 孤儿进程对系统无害, 孤儿进程会被init进程管理
  • 注意: Windows与类Unix系统创建子进程的方式不同

    • 类Unix

      • 类Unix系统采用fork()系统调用函数创建子进程, 字如其名, 子进程就是父进程的一个副本, 拷贝的过程中cs:ip的指针指向指令的哪个位置也是一致的(这多亏了虚拟内存), 也就是说, 复制出来的子进程不是从头开始执行的, 是从父进程调用fork()函数语句的下一条指令开始执行的, 随着技术的发展, fork()现在采用的是CoW实现
    • Windows

      • Windows上创建子进程的函数为CreateProcess(), 也是字如其名, 是创建一个进程而不是复制一个进程。CreateProcess()函数的API是


        BOOL CreateProcessA(
        LPCSTR lpApplicationName, // 进程要执行的.exe文件名
        LPSTR lpCommandLine, // 执行的.exe的命令行参数
        LPSECURITY_ATTRIBUTES lpProcessAttributes,
        LPSECURITY_ATTRIBUTES lpThreadAttributes,
        BOOL bInheritHandles,
        DWORD dwCreationFlags,
        LPVOID lpEnvironment,
        LPCSTR lpCurrentDirectory,
        LPSTARTUPINFOA lpStartupInfo,
        LPPROCESS_INFORMATION lpProcessInformation
        );

      - 我们主要看API的第1和第2个参数, 很明显, CreateProcess()API可以创建一个与当前父进程完全不同的子进程, 因为它接受一个.exe文件的路径, 该路径可以是任何一个.exe文件, 将该.exe文件加载到内存中***CPU从头开始执行代码***, 如果要实现与类Unix中fork()函数类似的功能, CreateProcess()的第一个参数应该为父进程的.exe文件的位置, 这样就创建出来一个与父进程一样的子进程了, 但是刚才说了是***类似***, 肯定有不同, ***类Unix中fork出来的子进程的入口是父进程fork语句的下一条指令, 而CreateProcess是从头开始执行子进程***
    • Windows底层采用CreateProcess函数创建子进程在Python中出现的问题

      • 在main.py中

        import time
        import multiprocessing
        from multiprocessing import Process def foo():
        time.sleep(3)
        print('this is foo function') p = Process(target=foo)
        p.start() print('Finish')
      • 在命令行执行python3 main.py, 报错: 常见了无限个进程
      • 分析
        • Windows 底层调用CreateProcess函数创建子进程, 创建的子进程会从头开始执行程序, 对于main.py, 创建一个子进程, 就会再走一遍import time..., 这个时候肯定还会遇到Process(), 没有办法, 在CreateProcess一次, 一次类推, 一直创建子进程

        • 解决方案

          • 依据Python中主进程的__name__ == __main__而子进程__name__ != __main__规避
          • 代码

          import time
          import multiprocessing
          from multiprocessing import Process def foo():
          time.sleep(3)
          print('this is foo function') if __name__ == '__main__':
          p = Process(target=foo)
          p.start()
          print('Finish')

进程共享

  • 一般来说进程中定义的数据是不会共享的, 父进程的数据与子进程中的数据无关, 对于一个一般的全局变量也是不共享的; 在这样势必会导致程序运行效率低下, 在Windows中在不同进程中打印id(an_obj), 显示出来的id是不同的, 因为Windows中的进程实质上不是fork出来的而是CreateProcessAPI产生的, 子进程要从头开始走一遍, 具体内容在上文注意中提到, 但是在类Unix中打印出来的id是一样的, 因为是fork出来的;

进程同步

  • 进程之间的数据是不共享的, 但是文件系统, 屏幕等是共享的, 可以共同访问一个文件, 一个屏幕(终端), 所以会产生这些资源的竞争, 为此我们需要控制他们的竞争关系
  • 为了控制资源的访问, 诞生了进程锁, 这里很特别, 我们知道两个进程(A与B)之间的资源是独立的, 但是multiprocessing中的对象(Lock, Queue等)在两个进程中内部会有复杂的映射, 目的就是要达到资源共享
    • 在main程序中定义了multiprocessing.Lock(), 在main中fork出A和B两个子进程执行一个同一段代码(代码一样, 但是不是同一段代码, 是复制出来的两份独立的代码), lock作为参数传入. A中lock.acquire()时, 按道理来说, 进程A与B是独立的, A中调用了acquire()应该不会影响B, 但是Python内部做了复杂的映射, 当A中lock.acquire()时也会对B中同一段代码上锁; 因为lock在内核空间

IPC

  • Queue(建议多使用Queue)

    0. Queue内部有锁机制, 并且支持数据共享

    1. q.put方法用以插入数据到队列中,put方法还有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,该方法会阻塞timeout指定的时间,直到该队列有剩余的空间。如果超时,会抛出Queue.Full异常。如果blocked为False,但该Queue已满,会立即抛出Queue.Full异常。
    2. q.get方法可以从队列读取并且删除一个元素。同样,get方法有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,那么在等待时间内没有取到任何元素,会抛出Queue.Empty异常。如果blocked为False,有两种情况存在,如果Queue有一个值可用,则立即返回该值,否则,如果队列为空,则立即抛出Queue.Empty异常.
    3. q.empty():调用此方法时q为空则返回True,该结果不可靠,比如在返回True的过程中,如果队列中又加入了项目。
    4. q.full():调用此方法时q已满则返回True,该结果不可靠,比如在返回True的过程中,如果队列中的项目被取走。
    5. q.qsize():返回队列中目前项目的正确数量,结果也不可靠,理由同q.empty()和q.full()一样
  • Pipe

    1. 与Linux C语言中的Pipe有一些不同, Python中的Pipe更加高级, C中的Pipe只能是父子进程之间进行数据交互, 但是Python中的Pipe除了父子之间还可以是其他的进程之间
    2. Pipe中一端recv或者send时, 如果所有其他端口都被close(所有涉及到该Pipe的进程)了, 才会抛出EOFError异常
    3. send(obj)和recv()方法使用pickle模块对对象进行序列化
    4. Pipe编程中的close(), send(), recv()等操作一定要在fork完了所有的进程执行, 否则会产生很多意想不到的错误
  • Manager(共享数据, 内部没有锁, 需要自己加锁)

    1. 就是C中的mmap
    2. 一般配合lock与with使用, 因为Manger自己不会加锁
    lock = Lock()
    with Manager() as m:
    d = m.dict({'data': 100})
    p = Process(target=foo, args=(d, lock))
    p.start()
  • Semaphore(信号量)

    1. 信号量规定了一个资源最多最多可以被多少个进程访问, 多出来的会被阻塞
    2. Semaphore(size)
    3. acquire() 锁资源
    4. release() 释放资源锁
  • Pool

    1. Pool(3), 创建一个有3个进程的进程池, 从无到有, 最多有3个, 之后就一直是3个
    2. apply 与 apply_async
      • apply

        • 同步执行进程, 会阻塞当前主进程
        • 会立即返回进程执行的结果
      • apply_async
        • 异步执行进程, 不会立即返回结果, 不会阻塞
        • 返回的对象为ApplyResult, 获取结果只需要调用对象的get方法, 但是调用get方法, 需要调用p.close(), 再调用p.join()方法之后才能取结果, 否则主程序结束了, 进程池中的任务还没来得及全部执行完也都跟着主进程一起结束了, 这与我们直接使用Process不同, 要获取结果get, 建议将所有的进程都执行完再批量查看结果

multiprocessing 模块的更多相关文章

  1. multiprocessing模块

    multiprocessing模块 由于GIL的存在,python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU的资源,在python中大部分情况需要使用多进程. multiproce ...

  2. 使用multiprocessing模块创建多进程

    # 使用multiprocessing模块创建多进程 # multiprcessing模块提供了一个Process类来描述一个进程对象. # 创建子进程时,只需要传入一个执行函数和函数的参数,即可完成 ...

  3. python MultiProcessing模块进程间通信的解惑与回顾

    这段时间沉迷MultiProcessing模块不能自拔,没办法,python的基础不太熟,因此就是在不断地遇到问题解决问题.之前学习asyncio模块学的一知半解,后来想起MultiProcessin ...

  4. 多进程Multiprocessing模块

    多进程 Multiprocessing 模块 先看看下面的几个方法: star() 方法启动进程, join() 方法实现进程间的同步,等待所有进程退出. close() 用来阻止多余的进程涌入进程池 ...

  5. Python第十五天 datetime模块 time模块 thread模块 threading模块 Queue队列模块 multiprocessing模块 paramiko模块 fabric模块

    Python第十五天  datetime模块 time模块   thread模块  threading模块  Queue队列模块  multiprocessing模块  paramiko模块  fab ...

  6. 进程初识和multiprocessing模块之Process

    一.什么是进程 进程就是运行中的程序 进程是操作系统中最小的资源分配单位 进程与进程之间的关系 : 数据隔离的 进程的id:Process id = pid pid是一个全系统唯一的对某个进程的标识, ...

  7. 30、进程的基础理论,并发(multiprocessing模块)

    我们之前基于tcp所做的通信都只能一个一个链接只有关闭当前链接时才能去链接下一个通信,这显然与现实情况不合.今天我们将来学一个新的概念进程,来做一个python多进程的并发编程.还会贴一个用json序 ...

  8. python多进程multiprocessing模块中Queue的妙用

    最近的部门RPA项目中,小爬为了提升爬虫性能,使用了Python中的多进程(multiprocessing)技术,里面需要用到进程锁Lock,用到进程池Pool,同时利用map方法一次构造多个proc ...

  9. Python之进程 2 - multiprocessing模块

    ​ 我们已经了解了,运行中的程序就是一个进程.所有的进程都是通过它的父进程来创建的.因此,运行起来的python程序也是一个进程,那么我们也可以在程序中再创建进程.多个进程可以实现并发效果,也就是说, ...

  10. python之多进程multiprocessing模块

    process类介绍 multiprocessing 模块官方说明文档 Process 类用来描述一个进程对象.创建子进程的时候,只需要传入一个执行函数和函数的参数即可完成 Process 示例的创建 ...

随机推荐

  1. NSUserDefaults数据存储

    前言 用来保存应用程序设置和属性.用户保存的数据.用户再次打开程序或开机后这些数据仍然存在. 如果往 userDefaults 里存了一个可变数组,取出来的时候这个数组对象就变成了不可变的. NSUs ...

  2. 1221: Fibonacci数列 [数学]

    1221: Fibonacci数列 [数学] 时间限制: 1 Sec 内存限制: 128 MB 提交: 116 解决: 36 统计 题目描述 Fibonacci数列的递推公式为:Fn=Fn-1+Fn- ...

  3. EF进阶篇(三)——上下文

    前言 上下文,到底什么是上下文,且听我仔细吹来. 内容 在对EF实体进行关系操作的时候,第一步需要我们创建上下文实例对象,然后根据实体的变化进而通过上下文对该实体进行状态的修改,我的理解就是上下文就是 ...

  4. 【bzoj3670】: [Noi2014]动物园 字符串-kmp-倍增

    [bzoj3670]: [Noi2014]动物园 一开始想的是按照kmp把fail算出来的同时就可以递推求出第i位要f次可以跳到-1 然后把从x=i开始顺着fail走,走到fail[x]*2<i ...

  5. django中itsdangerous的用法

    itsdangerous用来解决什么问题,为什么需要用到itsdangerous? 安装命令:pip install itsdangerous 有时候你想向不可信的环境发送一些数据,但如何安全完成这个 ...

  6. Docker - CentOS 安装 Docker 和 Docker-Compose

    目录 介绍 Docker Docker-Conpose 安装 Docker CE 系统要求 使用 YUM 安装 配置加速器 安装 Docker-Compose 介绍 Docker Docker 是一个 ...

  7. 加快npm包安装的方法

    一直以来都感觉使用npm安装包的速度特别的慢,但是由于npm上面的包比较齐全,所以一直在忍受这种安装依赖包的折磨. 不过这种折磨,到今天为止应该是可以结束了,在知乎看到一个这样的说法: 用npmins ...

  8. SDUT OJ 数据结构实验之排序八:快速排序

    数据结构实验之排序八:快速排序 Time Limit: 1000 ms Memory Limit: 65536 KiB Submit Statistic Problem Description 给定N ...

  9. 条目七《如果容器中包含了通过new操作创建的指针,切记在容器对象析构前将指针delete掉》

    如果容器中包含了通过new操作创建的指针,切记在容器对象析构前将指针delete掉 在STL中容器是智能的,可以在容器销毁时自动调用容器里对象的析构函数来销毁容器存储的对象. STL的容器虽然比较智能 ...

  10. 5. pytest的断言

    一.pytest 支持Python自带的标准断言 def f(): return 3 def test_function(): assert f() == 4 pytest 的断言报告,也很丰富,和详 ...