进程池与线程池
思考:能否无限制的开设进程或者线程???
肯定是不能无限制开设的
如果单从技术层面上来说无限开设肯定是可以的并且是最高效的
但是从硬件层面上来说是无法实现的(硬件的发展永远赶不上软件的发展速度)
什么是池?
在保证计算机硬件不奔溃的前提下开设多进程和多线程
降低了程序的运行效率但是保证了计算机硬件的安全
什么是用池?
池的功能是限制启动的进程数或线程数。
什么时候应该限制?
当并发的任务数远远超过了计算机的承受能力时,即无法一次性开启过多的进程数或线程数时
就应该用池的概念将开启的进程数或线程数限制在计算机可承受的范围内
进程池与线程池
进程池:提前开设了固定个数的进程 之后反复调用这些进程完成工作(后续不再开设新的)
线程池:提前开设了固定个数的线程 之后反复调用这些线程完成工作(后续不再开设新的)
进程池与线程池相结合使用,可以完美解决所缺的问题
开设进程池基本方法:
concurrent.futures模块提供了高度封装的异步调用接口
ThreadPoolExecutor:线程池,提供异步调用
ProcessPoolExecutor: 进程池,提供异步调用
Both implement the same interface, which is defined by the abstract Executor class.
#2 基本方法
#submit(fn, *args, **kwargs)
异步提交任务
#map(func, *iterables, timeout=None, chunksize=1)
取代for循环submit的操作
#shutdown(wait=True)
相当于进程池的pool.close()+pool.join()操作
wait=True,等待池内所有任务执行完毕回收完资源后才继续
wait=False,立即返回,并不会等待池内的任务执行完毕
但不管wait参数为何值,整个程序都会等到所有任务执行完毕
submit和map必须在shutdown之前
#result(timeout=None)
取得结果
#add_done_callback(fn)
回调函数
# done()
判断某一个线程是否完成
# cancle()
取消某个任务
进程池的使用
开设进程池(简易版)
import time
import os
import random
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
# 进程池 线程池
def task(n):
# 进程id
print(os.getpid(), '开始执行了')
time.sleep(3)
return n * n
if __name__ == '__main__':
# 开设进程池去执行 设置进程池大小
# ProcesspoolExecutor实列化得到一个对象
# 括号内可以传数字 不传的话默认会开设当前计算机cpu个数五倍
pool_p = ProcessPoolExecutor(3) # 限制每次最多有三个进程执行
for i in range(10):
# 把任务提交到进程池执行
# 函数(n=i) 指定参数
pool_p.submit(task, n=i)
print('我是主进程')
进程池 shutdown() : 等待所有进程池中的子进程执行结束再执行主进程(与.join相仿).
进程池进阶版shutdown代码块
import time
import os
import random
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
# 进程池 线程池
def task(n):
# 进程id
print(os.getpid(), '开始执行了')
time.sleep(1)
return n * n
if __name__ == '__main__':
# 开设进程池去执行 设置进程池大小
# ProcesspoolExecutor实列化得到一个对象
pool_p = ProcessPoolExecutor(3)
for i in range(10):
# 把任务提交到进程池执行
# 函数(n=i) 指定参数
pool_p.submit(task, n=i)
# 等待所有子进程执行完成,主进程在执行 默认为True
pool_p.shutdown()
print('我是主进程')
进程池 .result() :获取执行结果
》.result()使用代码块
import time
import os
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
# 进程池 线程池
def task(n):
# 进程id
print(os.getpid(), '开始执行了')
time.sleep(1)
return n * n
if __name__ == '__main__':
# 开设进程池去执行 设置进程池大小
# ProcesspoolExecutor实列化得到一个对象
pool_p = ProcessPoolExecutor(5)
# 定义空列表
ll = []
for i in range(10):
# 把任务提交到进程池执行
# 函数(n=i) 指定参数
f = pool_p.submit(task, n=i)
# 将返回值添加到列表
ll.append(f)
# 等待所有子进程执行完成,主进程在执行
pool_p.shutdown()
for l in ll:
# 取到当前进程执行任务的返回值
res = l.result()
print(res)
print('我是主进程')
进程池 .map()用法
点击查看代码
import time
import os
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
# 进程池 线程池
def task(n):
# 进程id
print(os.getpid(), '开始执行了')
time.sleep(1)
return n * n
if __name__ == '__main__':
# 开设进程池去执行 设置进程池大小
# ProcesspoolExecutor实列化得到一个对象
pool_p = ProcessPoolExecutor(3)
# for i in range(10):
# # 把任务提交到进程池执行
# # 函数(n=i) 指定参数
# f = pool_p.submit(task, n=i)
# 等同于上面两句执行结果
# map取代了for循环的,第一个参数是要执行的任务,第二个参数是可迭代对象
# 迭代一次的结果,会传给任务
pool_p.map(task, range(10))
# 等待所有子进程执行完成,主进程在执行
pool_p.shutdown()
print('我是主进程')
add_done_callback()回调函数
回调函数代码块
import time
import os
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
# 进程池 线程池
def task(n):
# 进程id
print(os.getpid(), '开始执行了')
# 执行任务处于就绪态,cpu调度谁就不一定了
time.sleep(1)
return n * n
def callback(result):
print(result.result())
if __name__ == '__main__':
# 开设进程池去执行 设置进程池大小
# ProcesspoolExecutor实列化得到一个对象
pool_p = ProcessPoolExecutor(1)
for i in range(10):
# 当任务执行完成后 会回调该函数(callback)
pool_p.submit(task, n=i).add_done_callback(callback)
# 等待所有子进程执行完成,主进程在执行
pool_p.shutdown()
print('我是主进程')
线程池
- 线程池与进程池的用法完全一样,只是更改为线程池模块。
- from concurrent.futures import ThreadPoolExecutor
- pool_p = ThreadPoolExecutor(线程数)
import time
import os
import random
from concurrent.futures import ThreadPoolExecutor
# 线程池
def task(n):
# 线程id
print(os.getpid(), '开始执行了')
time.sleep(3)
return n * n
if __name__ == '__main__':
# 开设线程池去执行 设置进程池大小
# ThreadPoolExecutor实列化得到一个对象
# 括号内可以传数字 不传的话默认会开设当前计算机cpu个数五倍
pool_p = ThreadPoolExecutor(1)
for i in range(10):
# 把任务提交到进程池执行
# 函数(n=i) 指定参数
pool_p.submit(task, n=i)
print('我是主线程')