目录
- 1. 线程的生命周期
- 2. 什么是线程池
- 3. 线程池功能介绍
- 4. ThreadPoolExecutor
1. 线程的生命周期
2. 什么是线程池
- 线程池的来源:线程在新建的时候需要系统进行资源分配,而在终止的时候则需要进行资源的回收。大量功能相同线程的新建与终止需要消耗大量的系统资源,那么我们能不能像一种方法,将这些功能相同的线程进行统一管理呢,避免大量的新建与终止从而节省系统资源。
- 线程池的具体操作方法:系统会维护一个任务清单,该清单中记录了等待程序执行的任务;同时维护一个线程池,池中保存了一定数量的线程。线程池中的线程在任务清单中接取任务并执行,在执行结束后并不终止而是重新接取任务。
3. 线程池功能介绍
- 节省资源:线程池的使用减少了大量线程新建与终止的开销
- 防御作用:避免因为建立太多的线程而导致的程序卡顿与终止的问题
- 代码整洁:使用线程池相较于直接创建线程更加整洁
- 适用场景:各线程执行时间较短;突发性大量请求。
4. ThreadPoolExecutor
- 导入库
from concurrent.futures imoprt ThreadPoolExecutor
- 定义方法
ThreadPoolExecutor(max_workers=...) # 定义一个最大线程数为max_workers的线程池
- 使用方法一——submit
with ThreadPoolExecutor() as pool:
futures = []
futures.append(pool.submit(target=func, args=(arg,)))
futures.append(pool.submit(...)
...
for future in futures:
print(future.result)
# submit方法会返回一个future对象,该方法并不是在线程执行完毕后才返回的,而是在调用方法的时候即返回。
# future对象可以监测一个线程执行的状态
# .result()得到进程返回结果
# .done()判断进程是否执行结束
# ...
- 使用方法二——map
with ThreadPoolExecutor(5) as pool:
futures = pool.map(func, args)
for future in futures:
print(future.result())
# .map()使用起来十分方便,func为线程的target方法,而args则是每个线程所需的arg的list。map方法与python本身的map方法思路相同,即args中的每一个参数都执行相同的func操作。
# 需要注意的是,使用map方法进行线程池的操作,起返回值futures是按args的传入顺序排列的。(即使各个thread的执行结束顺序与之不同)
- as_completed
from concurrent.futures import as_completed
with ThreadPoolExecutor(5) as pool:
futures = pool.map(func, args)
for future in as_completed(futures):
print(future.result())
# as_completed(futures)是一个生成器,它会判断futures中的进程是否完成执行,如果执行完成则yeild这个future。
# 因此使用a s_completed包裹的futures其输出的顺序是不固定的,这在一些场合是有必要的。