day9-进程池的使用
概述
之前不是说,多个进程间的内存都是独立的。在进程里面怎么也有锁的概念,为什么?虽然进程间都是独立运行的,但是他们共享同一块屏幕,所以为了避免打印出的数据不乱(加锁的情况下进程独占屏幕),所以加锁。
进程同步
用法:使用multiprocess模块中的Lock锁模块实现进程锁
#-*- coding:utf-8 -*-
from multiprocessing import Process, Lock
def f(l, i):
l.acquire() #获取锁
print('hello world', i)
l.release() #释放锁
if __name__ == '__main__':
lock = Lock() #生成锁的实例
for num in range(10): #启动10个进程
p = Process(target=f, args=(lock, num)) #将锁对象作为参数传给子进程f
p.start() #启动子进程
#运行输出
hello world 0
hello world 2
hello world 1
hello world 3
hello world 4
hello world 5
hello world 6
hello world 7
hello world 8
hello world 9
Process finished with exit code 0
进程池
作用:在使用Python处理并发任务时,最简单的模式就是主进程等待任务,当有新任务来到时,启动一个新的进程来处理当前任务。这种每个任务一个进程的处理方式,每处理一个任务都伴随着一个进程的创建,运行和销毁,如果进程的运行时间越短,创建和销毁的时间所占比重就越大,显然,我们应该尽量避免创建和销毁进程本身的额外开销,提高进程的运行效率。我们可以使用进程池来减少进程的创建和开销,提高进程对象的复用。
进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进程,那么程序就会等待,直到进程池中有可用的进程为止。
进程池的两个方法
1.apply
功能:同步执行也就是串行执行
from multiprocessing import Process, Pool #导入模块
import time,os
def Foo(i):
time.sleep(2)
print("in process:",os.getpid())
return i + 100
def Bar(arg):
print('-->exec done:', arg)
pool = Pool(5) #允许进程池里同时放入5个进程
for i in range(10): #启动10个进程
pool.apply(func=Foo, args=(i,)) #串行
print('end')
pool.close()
pool.join() # 进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭(不等进程执行完毕)。
#运行输出
in process: 32048
in process: 32049
in process: 32050
in process: 32051
in process: 32052
in process: 32048
in process: 32049
in process: 32050
in process: 32051
in process: 32052
end
Process finished with exit code 0
解析:串行执行的只有进程池中的5个,其他5个进程被挂起了。当进程池中进程执行结束一个,另外5个进程就进去一个,如此反复执行。直到全部执行结束。
2.apply_async
功能:异步执行也就是并发执行
from multiprocessing import Process, Pool
import time,os
def Foo(i):
time.sleep(2)
print("in process:",os.getpid())
return i + 100
def Bar(arg):
print('-->exec done:', arg)
pool = Pool(5) #允许进程池里同时放入5个进程
for i in range(10): #启动10个进程
pool.apply_async(func=Foo, args=(i,)) #并行
print('end')
pool.close()
pool.join() # 进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭(不等进程执行完毕)。
#运行输出
end
in process: 32114
in process: 32116
in process: 32117
in process: 32115
in process: 32118
in process: 32114
in process: 32116
in process: 32117
in process: 32115
in process: 32118
Process finished with exit code 0
解析:并行执行的只有进程池中的5个,其他5个进程被挂起了,等待5个同时执行结束,再放入进程池中另外5个,再同时执行。join()函数是等待所有进程池中的进程执行完毕后再关闭程序。没写的话,就是说不等进程执行结束与否,直接关闭程序。
在以上进程的并发方法中存在一个callback参数,它的作用可以实现回调,下面修改下例子
from multiprocessing import Process, Pool
import time,os
def Foo(i):
time.sleep(2)
print("in process:",os.getpid())
return i + 100
def Bar(arg):
print('-->exec done:%s 回调函数Bar的PID:%s'%(arg,os.getpid()))
pool = Pool(5) #允许进程池里同时放入5个进程
print("主进程的PID:",os.getpid())
for i in range(10): #启动10个进程
pool.apply_async(func=Foo, args=(i,),callback=Bar) #callback=回调
print('end')
pool.close()
pool.join() # 进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭(不等进程执行完毕)。
#输出
主进程的PID: 32163
end
in process: 32166
in process: 32165
in process: 32164
in process: 32168
in process: 32167
-->exec done:101 回调函数Bar的PID:32163
-->exec done:102 回调函数Bar的PID:32163
-->exec done:100 回调函数Bar的PID:32163
-->exec done:104 回调函数Bar的PID:32163
-->exec done:103 回调函数Bar的PID:32163
in process: 32165
-->exec done:105 回调函数Bar的PID:32163
in process: 32166
in process: 32164
in process: 32168
-->exec done:106 回调函数Bar的PID:32163
-->exec done:107 回调函数Bar的PID:32163
-->exec done:108 回调函数Bar的PID:32163
in process: 32167
-->exec done:109 回调函数Bar的PID:32163
Process finished with exit code 0
解析:可以看出每个子进程执行结束后都执行了Bar()函数,通过结果可以发现并不是子进程调用了Bar()函数,而是主进程执行了回调Bar()函数。
应用场景
启动10个进程到备份服务器上备份数据,备份完后要写一条日志到数据库。那么就可以使用回调函数实现单个进程(主进程)连接数据库,而不是10个子进程或更多的子进程,每次都调用Bar()函数启动10个或更多的进程同时连接到数据库,这样就节约了资源,提高了运行效率。

浙公网安备 33010602011771号