首页 技术 正文
技术 2022年11月7日
0 收藏 828 点赞 481 浏览 5623 个字

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 mpdef test():    passp = 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 mpimport osfrom time import sleepdef 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() # 等待进程池中的事件执行完毕,回收进程池

运行

8419hello-08418hello-18420hello-28421hello-38419hello-48418hello-58420hello-68421hello-78419hello-88418hello-9return: hello-0return: hello-1return: hello-2return: hello-3return: hello-4return: hello-5return: hello-6return: hello-7return: hello-8return: hello-9

这段代码运行较慢,和进程阻塞有关。相当于单线程!

当将代码(22行)中的 print(‘return:’,r)  修改为 print(‘return:’,r.get())  时

8670hello-08671hello-18672hello-28673hello-38670hello-48671hello-58672hello-68673hello-78670hello-88671hello-9Traceback (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 mpimport osfrom 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>8739874087428741hello-0hello-38742hello-187398740hello-28741hello-58739hello-68740hello-7hello-4hello-8hello-9

注意:

(1)由于这个是异步方式添加任务,所以运行非常快

(2)由于for是内置循环函数,执行效率较高,所以在结果的前10行均为for语句执行结果

(3) r = p.apply_async(worker,(msg,)) 执行结果为进度对象。

(4)由于任务是异步执行,所以在结果中是“乱序”;并不像applay那样有序打印。

同样将代码(22行)中的 print(‘return:’,r) 修改为 print(‘return:’,r.get())  时,

运行结果

8839884088418842hello-0hello-1hello-38839hello-2884288418840return: hello-0return: hello-1return: hello-2return: hello-3hello-4hello-58839hello-68842hello-7return: hello-4return: hello-5return: hello-6return: hello-7hello-9hello-8return: hello-8return: hello-9

在结果中出现“顺序混乱”

这与进程调度及运行时间有所差别有关,当有多个进程并行执行时,每个进程得到的时间片时间不一样,哪个进程接受那个求情以及执行完成时间都死不定的,所以输出会出现乱序的情况。

有时候还会出现两行数据出现在同一行,而下一行却为空行的情况,该情况可能时再执行第一个进程时,刚要打印换行符时,另一个进程也打印出来,这样就有可能本来两行的数据却在同一行打印出来,而两个换行符却次第打印出来,所以就会出现空行的情况。

注意:apply_async()函数本身就可以返回被进程调用的函数返回值。在创建子进程的代码中,若在被调用函数中返回一个值,那么pool.apply_async(func, (msg,))的结果就是返回pool中所有进程的“值的对象”(注意是对象,而不是值本身);同时对比不难发现,pool.apply的结果返回的是被调用函数的返回值,这里是值而不是对象。

比较使用进程池与函数之间

import timefrom multiprocessing import Pool def run(fn):    time.sleep(1)    return fn*fntest = [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开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:8,910
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,435
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,250
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,061
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,693
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,731