紧接着上篇进程后,今天继续更新进程池相关介绍
上篇介绍过,系统不可能无限的创建进程,它本身会收到CPU和内存的约束,这时候可以通过进程池来提高效率,节省开辟进程和开辟内存空间的时间及销毁进程的时间,另外进程池还可以节省内存空间。下面进入正篇:
什么是进程池
进程池顾名思义就是一个装进程的池子,可以提供指定数量的进程给用户使用,即当有新的请求提交到进程池中时,如果池未满,则会创建一个新的进程用来执行该请求;反之,如果池中的进程数已经达到规定最大值,那么该请求就会等待,只要池中有进程空闲下来,该请求就能得到执行。
为什么要使用进程池
提高效率,节省开辟进程和开辟内存空间的时间及销毁进程的时间;
节省内存空间。
如何创建进程池
import multiprocessing
pool=multiprocessing.Pool(num) #num代表进程池中的最大进程数
进程池Pool的常用方法及参数
参数:
processes : int类型参数,代表进程池最大进程数
方法:
apply(func=func) #同步阻塞式,必须要等待前一个子进程执行完后面才会继续执行
apply_async(func=func) #异步非阻塞式,不用等待当前运行的子进程执行完毕,随时根据系统调度来进行进程切换
补充:
同步和异步的区别:
同步:指一个进程在执行某个请求的时候,必须要到收到对方返回的信息才继续执行下去;
异步:指进程在执行某个请求时,不管其他的进程的状态,这个进程就执行后续操作;当有消息返回时系统会通知进程进行处理,这样可以提高执行的效率
例如:打电话就是同步通信,发信息就是异步通信。
同步:
同步阻塞式
import multiprocessing
import os, time
def work():
print(f'进程名{multiprocessing.current_process().name},进程号{os.getpid()}')
time.sleep(1)
if __name__ == '__main__':
print('--------开始主进程------------')
print(f'主进程名{multiprocessing.current_process().name},进程号{os.getpid()}')
start_time = time.time()
pool = multiprocessing.Pool(4)
for i in range(1, 6):
pool.apply(func=work)
pool.close()
pool.join()
time.sleep(5)
end_time = time.time()
print(f'----------主进程结束,耗时:{end_time - start_time}-------------------')
####运行输出结果:
#--------开始主进程------------
#主进程名MainProcess,进程号15460
#进程名SpawnPoolWorker-1,进程号19208
#进程名SpawnPoolWorker-2,进程号7112
#进程名SpawnPoolWorker-3,进程号19112
#进程名SpawnPoolWorker-4,进程号7244
#进程名SpawnPoolWorker-1,进程号19208
#----------主进程结束,耗时:10.170766353607178-------------------
异步:
#异步非阻塞式
import multiprocessing
import os, time
def work():
print(f'进程名{multiprocessing.current_process().name},进程号{os.getpid()}')
time.sleep(1)
if __name__ == '__main__':
print('--------开始主进程------------')
print(f'主进程名{multiprocessing.current_process().name},进程号{os.getpid()}')
start_time = time.time()
pool = multiprocessing.Pool(4)
for i in range(1, 6):
pool.apply_async(func=work)
pool.close()
pool.join()
time.sleep(5)
end_time = time.time()
print(f'----------主进程结束,耗时:{end_time - start_time}-------------------')
#####运行输出结果:
#--------开始主进程------------
#主进程名MainProcess,进程号11252
#进程名SpawnPoolWorker-1,进程号14152
#进程名SpawnPoolWorker-2,进程号6236
#进程名SpawnPoolWorker-4,进程号18728
#进程名SpawnPoolWorker-3,进程号18932
#进程名SpawnPoolWorker-4,进程号18728
#----------主进程结束,耗时:7.170076608657837-------------------
对比上面两段代码,明显可以看到异步的执行效率远高于同步,故而异步是我们的首选。
python官方指导文档也有关于这块的介绍:
官方文档关于apply()的介绍
Call func with arguments args and keyword arguments kwds. It blocks until the result is ready. Given this blocks, apply_async() is better suited for performing work in parallel. Additionally, func is only executed in one of the workers of the pool.
terminate() #立刻关闭进程池
join() #主进程等待所有子进程执行完毕,必须在close或terminete之后
close() #等待所有进程结束才关闭线程池
terminate使用:
import multiprocessing
import os, time
def work():
print(f'进程名{multiprocessing.current_process().name},进程号{os.getpid()}')
time.sleep(1)
if __name__ == '__main__':
print('--------开始主进程------------')
print(f'主进程名{multiprocessing.current_process().name},进程号{os.getpid()}')
start_time = time.time()
pool = multiprocessing.Pool(4)
for i in range(1, 6):
pool.apply_async(func=work)
time.sleep(1)
pool.terminate()
pool.join()
end_time = time.time()
print(f'----------主进程结束,耗时:{end_time - start_time}-------------------')
####运行结果输出:
#--------开始主进程------------
#主进程名MainProcess,进程号17872
#进程名SpawnPoolWorker-1,进程号17280
#进程名SpawnPoolWorker-2,进程号8600
#进程名SpawnPoolWorker-3,进程号1016
#进程名SpawnPoolWorker-4,进程号7184
#----------主进程结束,耗时:1.050588607788086-------------------
close()使用:
import multiprocessing
import os, time
def work():
print(f'进程名{multiprocessing.current_process().name},进程号{os.getpid()}')
time.sleep(1)
if __name__ == '__main__':
print('--------开始主进程------------')
print(f'主进程名{multiprocessing.current_process().name},进程号{os.getpid()}')
start_time = time.time()
pool = multiprocessing.Pool(4)
for i in range(1, 6):
pool.apply_async(func=work)
time.sleep(1)
pool.close()
pool.join()
end_time = time.time()
print(f'----------主进程结束,耗时:{end_time - start_time}-------------------')
#####运行结果输出:
#--------开始主进程------------
#主进程名MainProcess,进程号19360
#进程名SpawnPoolWorker-1,进程号17640
#进程名SpawnPoolWorker-2,进程号18588
#进程名SpawnPoolWorker-4,进程号18404
#进程名SpawnPoolWorker-3,进程号18376
#进程名SpawnPoolWorker-1,进程号17640
#----------主进程结束,耗时:2.1518847942352295-------------------
通过terminal和close两段代码对比可以明显看出两者差异