2020.9.28 多进程multiprocess 进程池pool 子进程subprocess 进程间通信

1、multiprocessing模块——跨平台版本的多进程模块

 

multiprocessing模块提供了一个Process类来代表一个进程对象,下面的例子演示了启动一个子进程并等待其结束:

 

复制代码
from multiprocessing import Process
import os

#子进程要执行的代码
def run_proc(name):
    print('Run child process %s (%s)…'%(name , os.getpid()))

if __name__=='__main__':
    print('parent process %s.'%os.getpid())
    p=Process(target=run_proc,args=('test',))
    print('Child process will start')
    p.start()
    p.join()
    print('Child process end')

parent process 14960.
Child process will start
Run child process test (12496)…
Child process end
复制代码

上述代码的说明:

1、父进程的进程ID的获取,通过os.getpid()

2、创建子进程时,用到了语句

p=Process(target=run_proc,args=('test',))

只需传入一个执行函数的函数名(如上文的run_proc)和函数的参数(args,注意一个参数时括号中的逗号),如此构造一个Process实例,并用start()启动。

join()方法可以等待子进程结束后继续往下执行,通常用于进程间的同步。

 

2、Pool

如果要创建大量进程,可以通过进程池的方式批量创建子进程:

复制代码
from multiprocessing import Pool
import os,time,random

def long_time_task(name):
    print('run task %s (%s)'%(name,os.getpid()))
    start=time.time()
    time.sleep(random.random()*3)
    end=time.time()
    print('task %s runs %.2fs'%(name,end-start))

if __name__=='__main__':
    print('parent process %s '%os.getpid())
    p=Pool(4)
    for i in range(5):
        p.apply_async(long_time_task,args=(i,))
    print('Waiting for all subprocesses done…')
    p.close()
    p.join()
    print('All subprocesses done')
复制代码
复制代码
parent process 5280 
Waiting for all subprocesses done…
run task 0 (2768)
run task 1 (12844)
run task 2 (15340)
run task 3 (7612)
task 1 runs 0.33s
run task 4 (12844)
task 0 runs 1.45s
task 2 runs 2.01s
task 3 runs 2.91s
task 4 runs 2.89s
All subprocesses done
复制代码

上述代码的说明:

1、对Pool对象调用join()方法会等待所有子进程执行完毕,调用join()前必须先调用close(),调用close()后就不能再添加新的process了

2、输出结果中,task0,1,2,3是立即执行的,而task4要等前面的某个task执行完后才能执行,这是因为我们之前人为设置了Pool的大小为4,因此最多同时执行4个进程。这是人为根据需要制定的,并不是操作系统的限制,如果我们改为

p=Pool(5)

就可以同时跑5个进程。

Pool的默认大小是CPU的核数。

 

3、子进程subprocess

很多时候,子进程不是自身,而是一个外部进程。——暂未理解这句话啥意思

我们创建子进程后,还要控制子进程的输入和输出。

subprocess模块可以让我们非常方便地启动一个子进程,然后控制其输入输出。

 

举例:在Python代码中运行命令 

nslookup www.python.org

来达到和命令行同时运行相同的效果。

import subprocess
print('$ nslookup www.python.org')
r=subprocess.call(['nslookup','www.python.org'])
print('Exit Code:',r)
复制代码
$ nslookup www.python.org
��Ȩ��Ӧ��:
������:  public1.114dns.com
Address:  114.114.114.114
����:    dualstack.python.map.fastly.net
Addresses:  2a04:4e42:36::223
      151.101.108.223
Aliases:  www.python.org
Exit Code: 0
复制代码

如果子进程还需要输入,则可以通过communicate()方法输入:

import subprocess
print('$nslookup www.python.org')
p=subprocess.Popen(['nslookup'],stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
output,err=p.communicate(b'set q=mx\npython.org\nexit\n')
print(output.decode('utf-8'))
print('Exit Code:',p.returncode)

其中

p.communicate(b'set q=mx\npython.org\nexit\n')

相当于在命令行执行命令nslookup,然后手动输入:

set q=mx
python.org
exit

 

4、进程间通信

Python的multiprocessing模块提供了Queue、Pipes等多种方式来交换数据。

以Queue为例,在父进程中创建两个子进程,一个往Queue中写数据,另一个从Queue中读数据:

复制代码
from multiprocessing import Queue,Process
import os,time,random

#写数据进程要执行的代码
def write(q):
    print('Process to write:%s'%os.getpid())
    for value in ['A','B','C']:
        print('put %s to queue'%value)
        q.put(value)
        time.sleep(random.random())

#读数据进程执行的代码
def read(q):
    print('Process to read:%s'%os.getpid())
    while True:
        value=q.get(True)
        print('Get %s from queue.'%value)

if __name__=='__main__':
    #父进程创建Queue并传给各个子进程
    q=Queue()
    pw=Process(target=write,args=(q,))
    pr=Process(target=read,args=(q,))
    #启动子进程pw,写入
    pw.start()
    #启动子进程pr,读取
    pr.start()

    #等待pw结束
    pw.join()
    #pr进程里是死循环,无法自行终止,只能强行结束
    pr.terminate()
复制代码

结果:

Process to write:2696
put A to queue
Process to read:7944
Get A from queue.
put B to queue
Get B from queue.
put C to queue
Get C from queue.

 

Unix/Linux下,multiprocessing模块封装了fork()调用,使我们不需要关注fork()的细节。由于Windows没有fork调用,因此multiprocessing需要模拟出fork的效果,父进程中所有Python对象都必须通过pickle序列化再传到子进程中去,所以如果multiprocessing在Windows下失效了,要先考虑是不是pickle失败

posted @   ShineLe  阅读(338)  评论(0编辑  收藏  举报
编辑推荐:
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
阅读排行:
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
点击右上角即可分享
微信分享提示