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失败了
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性