
进程池
在利用Python进行系统管理的时候,特别是同时操作多个文件目录,或者远程控制多台主机,并行操作可以节约大量的时间.
当被操作对象数目不大时,可以直接利用
multiprocessing.Process
动态成生多个进程,十几个还好,但如果是上百个,上千个目标,手动的去限制进程数量却又太过繁琐,此时可以发挥进程池的功效
Pool
可以提供指定数量的进程,供用户调用.当有新的请求提交到pool
中时,如果进程池还没有满,那么就会创建一个新的进程用来执行该请求, 但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束.才会创建新的进程来它
multiprocessing.Pool()
类有以下方法:
函数 解释 apply_async(func[,args[,kwargs[,callback]]])
不阻塞主进程,但是 callback
阻塞调用它的进程,异步操作apply(func[,args[,kwargs]])
使用阻塞的方式调用func close()
关闭pool, 使其不在接收新的任务 terninate()
不管任务是否完成,立即终止 join()
主进程阻塞,等待子进程的退出,必须在 close\ terminate
之后使用
apply(func[,args[,kwargs[,callback[,error_callback]]]])
: 返回一个结果对象,首先这是一个异步操作,如果指定了callback
,它必须是一个接受单个参数的可调用对象.当执行成功后,ballback
会被用与处理执行后的执行结果,否则调用error_callback
,如果指定了error_callback
,它必须是一个接受单个参数的可调用对象,当目标函数执行失败后,会将抛出的异常传递给error_callback
处理.回调函数应该立即执行完成,否则会阻塞负责处理结果的线程或进程.
1.创建进程池
apply_async()
使用非阻塞异步的方式创建进程池:
- 非阻塞指的是不会阻塞主进程
- 异步指的是主进程不用等待调用结果,可以运行主进程中其他代码,等待子进程信号的回馈.
import multiprocessing,time
# 异步非阻塞的
def worker1():
print('子进程:{},开始于:{}'.format(multiprocessing.current_process().name, time.time()))
i = 0
for j in range(10000):
i = i+j
print('子进程:{},结束于:{}'.format(multiprocessing.current_process().name, time.time()))
return i
if __name__ == '__main__':
"""主进程"""
print('主进程,开始于:{}'.format(time.time()))
pool = multiprocessing.Pool(2)
for i in range(4):
pool.apply_async(worker1) # 异步
print('-------------------')
print('这是主进程在子进程后执行的部分:{}'.format(time.time()))
print('-------------------')
pool.close()
pool.join()
print('主进程结束:{}'.format(time.time()))处理结果:
主进程,开始于:1572770657.2222323
-------------------
这是主进程在子进程后执行的部分:1572770657.2364972
-------------------
子进程:ForkPoolWorker-1,开始于:1572770657.2367756
子进程:ForkPoolWorker-2,开始于:1572770657.2368524
子进程:ForkPoolWorker-2,结束于:1572770657.2377691
子进程:ForkPoolWorker-2,开始于:1572770657.23802
子进程:ForkPoolWorker-1,结束于:1572770657.2383952
子进程:ForkPoolWorker-1,开始于:1572770657.2386503
子进程:ForkPoolWorker-2,结束于:1572770657.2388988
子进程:ForkPoolWorker-1,结束于:1572770657.240224
主进程结束:1572770657.3381264
apply()
使用阻塞同步创建进程池:
- 阻塞是指只有一个进程处理完后,另外一个进程才会处理
- 同步指的是,主进程必须等待返回的结果,只有当结果返回后才会执行主程序
import multiprocessing,time
def worker1():
print('子进程:{},开始于:{}'.format(multiprocessing.current_process().name, time.time()))
i = 0
for j in range(10000):
i = i+j
print('子进程:{},结束于:{}'.format(multiprocessing.current_process().name, time.time()))
return i
if __name__ == '__main__':
"""主进程"""
print('主进程,开始于:{}'.format(time.time()))
pool = multiprocessing.Pool(2)
for i in range(4):
pool.apply(worker1) # 同步
print('-------------------')
print('这是主进程在子进程后执行的部分:{}'.format(time.time()))
print('-------------------')
pool.close()
pool.join()
print('主进程结束:{}'.format(time.time()))处理结果:
主进程,开始于:1572770654.673824
子进程:ForkPoolWorker-1,开始于:1572770654.687851
子进程:ForkPoolWorker-1,结束于:1572770654.688698
子进程:ForkPoolWorker-2,开始于:1572770654.6891456
子进程:ForkPoolWorker-2,结束于:1572770654.6897376
子进程:ForkPoolWorker-1,开始于:1572770654.6900878
子进程:ForkPoolWorker-1,结束于:1572770654.6906323
子进程:ForkPoolWorker-2,开始于:1572770654.6908329
子进程:ForkPoolWorker-2,结束于:1572770654.691444
-------------------
这是主进程在子进程后执行的部分:1572770654.691627
-------------------
主进程结束:1572770654.7890923对比两个返回结果.注意
主程序在子程序之后运行的部分这句话
: 这体现了异步的好处,主进程可以不用等待子进程而自己运行代码.对比两个返回结果,阻塞的程序必须一个一个的运行,因为阻塞了主程序,导致新的子程序不能生成,而不阻塞,则可以产生并行更多的子程序.
2.进程池调用Queue
队列
- END -
import multiprocessing
def worker1(queue):
for i in range(10):
queue.put('worker1:{}'.format(i))
def worker2(queue):
for i in range(10, 20):
queue.put('worker2:{}'.format(i))
def consumer(queue):
print(queue.qsize())
for i in range(queue.qsize()):
ret = queue.get_nowait()
print(ret)
if __name__ == '__main__':
queue = multiprocessing.Manager().Queue()
pool1 = multiprocessing.Pool(2)
pool1.apply(worker1, (queue, ))
pool1.apply(worker2, (queue, ))
pool2 = multiprocessing.Pool(2)
pool2.apply(consumer, (queue, ))
pool1.close()
pool1.join()
pool2.close()
pool2.join()可以生成2个进程池,一个用来管理
Queue
中的写入,一个用来管理读取