python学习笔记——multiprocessing 多进程组件 进程池Pool
1 进程池Pool基本概述
在使用Python进行系统管理时,特别是同时操作多个文件目录或者远程控制多台主机,并行操作可以节约大量时间,如果操作的对象数目不大时,还可以直接适用Process类动态生成多个进程,几十个尚可,若上百个甚至更多时,手动限制进程数量就显得特别繁琐,此时进程池就显得尤为重要。
进程池Pool类可以提供指定数量的进程供用户调用,当有新的请求提交至Pool中时,若进程池尚未满,就会创建一个新的进程来执行请求;若进程池中的进程数已经达到规定的最大数量,则该请求就会等待,直到进程池中有进程结束,才会创建新的进程来处理该请求。
进程池不用频繁创建和销毁进程
2 进程池Pool的语法
Pool([processes[, initializer[, initargs[, maxtasksperchild[, context]]]]])
processes:使用的工作进程的数量;若processes是None,默认适用os.cpu_count()返回的数量。
initializer:若initializer是None,则每一个工作进程在开始的时候就会调用initializer(*initargs)。
maxtasksperchild:工作进程退出前可以完成的任务数,完成后用一个新的工作进程来替代原进程,让闲置的资源释放,maxtasksperchild默认是None,此意味只要Pool存在工作进程就一直存活
context: 用在制定工作进程启动时的上下文,一般使用multiprocessing.Pool()或者一个context对象的Pool()方法来创建一个池,两种方法都适当的设置了context。
如果主进程退出,则进程池中的所有进程均退出。
使用Pool创建进程池对象,同时进程池中进程已经启动,向进程池中添加事件时,事件排队执行。
实例方法:
p为进程池对象
p.apply():
apply(func[, args=()[, kwds={}]])
该函数用于传递不定参数,主进程会被阻塞直到函数执行结束,实际上这也就说所谓的同步执行。
同步执行,按照加入进程池的顺序执行事件,每次执行完一个再执行另一个,无法获取返回值。
p.apply_async()
apply_async(func[, args=()[, kwds={}[, callback=None]]])
与apply用法一样,但它是非阻塞且支持结果返回进行回调;实际上也就是异步执行。
异步执行,同时启动进程池中多个进程执行事件,可以获取事件返回值 — <multiprocessing.pool.ApplyResult object at 0x7f7f6e4357f0>。
p.map()
map(func, iterable[, chunksize=None])
Pool类中的map方法,与内置map函数用法基本一致,它融合了map函数和apply_async()函数的功能;它会使进程阻塞直到返回结果。
注意:虽然第二个参数是一个迭代器,但实际应用中,必须在整个队列就绪后,程序才会运行子进程。
p.close():关闭进程池,阻止更多的任务提交到进程池Pool,待任务完成后,工作进程会退出
p.terminate():结束工作进程,不再处理未完成的任务
p.join():等待工作线程的退出,必须在close()或terminate()之后使用,因被终止的进程需要被父进程调用wait(join等价于wait),否则进程会成为僵尸进程。
注意:
(1)使用Pool创建进程池对象,同时进程池中进程已经启动
(2)向进程池对象中添加事件,事件排队执行
(3)如果主进程退出,则进程池中所有进程都退出
3 实例
3.1 基础实例
import multiprocessing as mp def test(): pass p = mp.Pool(processes = 5) # 创建5条进程 for i in range(10): p.apply_async(test) # 向进程池添加任务 p.close() # 关闭进程池,不再接受请求 p.join() # 等待所有的子进程结束
说明:
(1)进程池Pool被创建出来后, p.apply_async(test) 语句不停地循环执行,相当于向进程池中提交了10个请求,它们会被放到一个队列中。
(2) p = mp.Pool(5) 执行完毕后创建了5条进程,但尚未给它们分配各自的任务;也就意味着,无论有多少任务,实际的进程数只有5条,每次最多5条进程并行。
(3)当Pool中有进程任务执行完毕后,这条进程资源会被释放,Pool会按先进先出的原则取出一个新的请求给空闲的进程继续执行。
(4)当Pool所有的进程任务完成后,会产生5个僵尸进程,如果主进程/主线程不结束,系统不会自动回收资源,需要调用join函数负责回收。
(5)在创建Pool进程池时,若不指定进程的最大数量,默认创建的进程数为系统的内核数量
(6)如果采用p.apply(test)阻塞方式添加任务,其每次只能向进程池中添加一条任务,然后for循环会被阻塞等待,直到添加的任务被执行完毕,进程池中的5个进程交替执行新来的任务,此时相当于单进程。——该语句需要再深刻理解,尚未完全明白
参考:python的multiprocessing模块进程创建、资源回收-Process,Pool
3.2 apply方式添加任务
import multiprocessing as mp import os from time import sleep def worker(msg): print(os.getpid()) sleep(2) print(msg) return msg #创建进程池对象 p = mp.Pool(processes = 4)#创建4条进程 pool_result = [] for i in range(10): msg = 'hello-%d'%i r = p.apply(worker,(msg,)) #向进程池中添加事件,该语句为同步执行, #没有返回值,这种方法用的比较少 r = p.apply(worker,(msg,)) pool_result.append(r)
#获取事件函数的返回值 for r in pool_result: print('return:',r) p.close()# 关闭进程池,不再接受请求,不能再向里面添加事件 p.join() # 等待进程池中的事件执行完毕,回收进程池
运行
8419 hello-0 8418 hello-1 8420 hello-2 8421 hello-3 8419 hello-4 8418 hello-5 8420 hello-6 8421 hello-7 8419 hello-8 8418 hello-9 return: hello-0 return: hello-1 return: hello-2 return: hello-3 return: hello-4 return: hello-5 return: hello-6 return: hello-7 return: hello-8 return: hello-9
这段代码运行较慢,和进程阻塞有关。相当于单线程!
当将代码(22行)中的 print('return:',r) 修改为 print('return:',r.get()) 时
8670 hello-0 8671 hello-1 8672 hello-2 8673 hello-3 8670 hello-4 8671 hello-5 8672 hello-6 8673 hello-7 8670 hello-8 8671 hello-9 Traceback (most recent call last): File "test1.py", line 22, in <module> print('return:',r.get()) AttributeError: 'str' object has no attribute 'get'
最后报错: AttributeError: 'str' object has no attribute 'get'
3.3 applay_async方式添加任务
import multiprocessing as mp import os from time import sleep def worker(msg): print(os.getpid()) sleep(2) print(msg) return msg #创建进程池对象 p = mp.Pool(processes = 4) #创建4条进程 pool_result = [] for i in range(10): msg = 'hello-%d'%i r = p.apply_async(worker,(msg,)) #向进程池中添加事件 pool_result.append(r) #获取事件函数的返回值 for r in pool_result: print('return:',r) p.close()#关闭进程池,不再接受请求 p.join()# 等待进程池中的事件执行完毕,回收进程池
运行
return: <multiprocessing.pool.ApplyResult object at 0x7f66d0e37d68> return: <multiprocessing.pool.ApplyResult object at 0x7f66d0e37e80> return: <multiprocessing.pool.ApplyResult object at 0x7f66d0e37f98> return: <multiprocessing.pool.ApplyResult object at 0x7f66d0e410f0> return: <multiprocessing.pool.ApplyResult object at 0x7f66d0e41208> return: <multiprocessing.pool.ApplyResult object at 0x7f66d0e41320> return: <multiprocessing.pool.ApplyResult object at 0x7f66d0e41438> return: <multiprocessing.pool.ApplyResult object at 0x7f66d0e41550> return: <multiprocessing.pool.ApplyResult object at 0x7f66d0e41668> return: <multiprocessing.pool.ApplyResult object at 0x7f66d0e41780> 8739 8740 8742 8741 hello-0 hello-3 8742 hello-1 8739 8740 hello-2 8741 hello-5 8739 hello-6 8740 hello-7 hello-4 hello-8 hello-9
注意:
(1)由于这个是异步方式添加任务,所以运行非常快
(2)由于for是内置循环函数,执行效率较高,所以在结果的前10行均为for语句执行结果
(3) r = p.apply_async(worker,(msg,)) 执行结果为进度对象。
(4)由于任务是异步执行,所以在结果中是“乱序”;并不像applay那样有序打印。
同样将代码(22行)中的 print('return:',r) 修改为 print('return:',r.get()) 时,
运行结果
8839 8840 8841 8842 hello-0 hello-1 hello-3 8839 hello-2 8842 8841 8840 return: hello-0 return: hello-1 return: hello-2 return: hello-3 hello-4 hello-5 8839 hello-6 8842 hello-7 return: hello-4 return: hello-5 return: hello-6 return: hello-7 hello-9 hello-8 return: hello-8 return: hello-9
在结果中出现“顺序混乱”
这与进程调度及运行时间有所差别有关,当有多个进程并行执行时,每个进程得到的时间片时间不一样,哪个进程接受那个求情以及执行完成时间都死不定的,所以输出会出现乱序的情况。
有时候还会出现两行数据出现在同一行,而下一行却为空行的情况,该情况可能时再执行第一个进程时,刚要打印换行符时,另一个进程也打印出来,这样就有可能本来两行的数据却在同一行打印出来,而两个换行符却次第打印出来,所以就会出现空行的情况。
注意:apply_async()函数本身就可以返回被进程调用的函数返回值。在创建子进程的代码中,若在被调用函数中返回一个值,那么pool.apply_async(func, (msg,))的结果就是返回pool中所有进程的“值的对象”(注意是对象,而不是值本身);同时对比不难发现,pool.apply的结果返回的是被调用函数的返回值,这里是值而不是对象。
比较使用进程池与函数之间
import time from multiprocessing import Pool def run(fn): time.sleep(1) return fn*fn test = [1,2,3,4,5,6,7,8] s = time.time() for fn in test: run(fn) e = time.time() print('执行时间:',e - s) pool = Pool(3) #使用该模块中的map融合了原map函数和该模块中apply_async函数 r = pool.map(run,test) pool.close() pool.join() e1 = time.time() print('执行时间:',e1 - e)
运行
执行时间: 8.011977195739746 执行时间: 3.0851333141326904
参考
Python多进程库multiprocessing中进程池Pool类的使用
Python 多进程 multiprocessing.Pool类详解
python学习笔记——multiprocessing 多进程组件 进程池Pool的更多相关文章
- python学习笔记——multiprocessing 多进程组件-队列Queue
1 消息队列 1.1 基本语法 消息队列:multiprocessing.Queue,Queue是对进程安全的队列,可以使用Queue实现对进程之间的数据传输:还有一个重要作用是作为缓存使用. Que ...
- python学习笔记——multiprocessing 多进程组件 Pipe管道
进程间通信(IPC InterProcess Communication)是值在不同进程间传播或交换信息. IPC通过有管道(无名管道 和 有名 / 命名管道).消息队列.共享存储 / 内容.信号量. ...
- python学习笔记——multiprocessing 多进程模块Process
系统自带的fork模块创建的多进程是基于Linux或Unix平台的,而window平台并不支持: python中的multiprocess为跨平台版本的多进程模块,支持子进程.通信和共享数据.执行不同 ...
- python学习笔记——multiprocessing 多进程中的重构方法__init__
重构: import multiprocessing import time class ClockProcesses(multiprocessing.Process): def __init__(s ...
- python学习笔记12 ----线程、进程
进程和线程的概念 进程和线程是操作系统中两个很重要的概念,对于一般的程序,可能有若干个进程,每一个进程有若干个同时执行的线程.进程是资源管理的最小单位,线程是程序执行的最小单位(线程可共享同一进程里的 ...
- python学习笔记11 ----线程、进程、协程
进程.线程.协程的概念 进程和线程是操作系统中两个很重要的概念,对于一般的程序,可能有若干个进程,每一个进程有若干个同时执行的线程.进程是资源管理的最小单位,线程是程序执行的最小单位(线程可共享同一进 ...
- Python 3 并发编程多进程之进程池与回调函数
Python 3 进程池与回调函数 一.进程池 在利用Python进行系统管理的时候,特别是同时操作多个文件目录,或者远程控制多台主机,并行操作可以节约大量的时间.多进程是实现并发的手段之一,需要注意 ...
- python学习笔记09--线程、进程
本节内容 一.进程与线程的概念 1.1进程 1.2线程 1.3进程与线程的区别 二.线程 2.1启一个线程 2.2线程的2种调用方式 2.3 join 2.4 守护线程Daemon 2.5线程锁 2. ...
- 2020.9.28 多进程multiprocess 进程池pool 子进程subprocess 进程间通信
1.multiprocessing模块--跨平台版本的多进程模块 multiprocessing模块提供了一个Process类来代表一个进程对象,下面的例子演示了启动一个子进程并等待其结束: from ...
随机推荐
- iOS开发-音乐播放
现在的各种App大行其道,其实常用也就是围绕着吃喝玩乐基本的需求,视频,音乐在智能手机出现之前更是必不可少的功能,每个手机都会有一个自带的音乐播放器,当然公众也有自己的需求所以也就造就了各种音乐播放软 ...
- Android导航抽屉-Navigation Drawer
Google今年七月份的时候更新了他们的Google+应用,采用了新的导航方式并抛弃了navigationdrawer.一时之间,又引发了一系列关于NavigationDrawer利弊的讨论,不过对于 ...
- Android动画-补间(Tween)动画
Android动画的两种方式,其中帧动画上篇文章已经讲了,这次主要讲解的就是补间动画,补间动画就是动画业务场景中常用的旋转,平移,缩放,和渐变效果,帧动画是通过轮播动画实现动画效果,补间动画通过在两个 ...
- Java 解析Excel文件为JSON
Excel转Json的需求 反正我对SSM基本不会的情况下来到现在这家公司,都是90后,感觉很好.第二天就给我开发任务,就是把用户上传的Excel文件转成JSON返回给前台用于大屏的数据展示. 解决方 ...
- C# 中使用 RSA加解密算法
一.什么是RSA RSA公开密钥密码体制.所谓的公开密钥密码体制就是使用不同的加密密钥与解密密钥,是一种“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制. 在公开密钥密码体制中,加密密钥(即 ...
- 如果不用jQuery,Ajax你还能写出多少?
许久之前发过一篇关于Ajax的博客,通篇讲的都是通过jQuery编写Ajax,可能因为jQuery在这方面做的实在太好,以至于突然发现不用jQuery的话自己都模糊了Ajax的写法,这里重温一下. F ...
- linux下设置 git ssh 代理
/root/.ssh (以下为 root权限的操作) 1. 生成key. $ ssh-keygen 一路回车,直到生成 id_rsa, id_rsa.pub 1.1 chmod 400 id_rsa. ...
- 2013级C++第14周(春)项目——多态性、虚函数和抽象类
课程首页在:http://blog.csdn.net/sxhelijian/article/details/11890759,内有完整教学方案及资源链接 第一部分 阅读程序1.阅读.改动和执行关于交通 ...
- Discuz 学习笔记一 :getgdc 和get_client_ip
Getgdc函数 discuz有一个超级变量的自定义函数: function getgpc($k, $type='GP') { $type = strtoupper($type); ...
- Service具体解释(二):Service生命周期
< Service具体解释(一):什么是Service> < Service具体解释(二):Service生命周期> <Service具体解释(三):Service的使用 ...