106、Python并发编程:深入浅出理解线程池的内部实现原理

引言

前面一篇文章中,我们介绍了通过Python中的ThreadPoolExecutor,也就是线程池更加灵活便捷地实现了Python中的多线程编程。

在Python的多线程编程中,有一个默认的原则是:"如果多线程编程不可避免,那么请尽量使用ThreadPoolExecutor来实现"。足以看到,线程池的重要性。

那么本文在对线程池的使用有一定的基础之上,稍微深入一下线程池的内部设计及实现,从而加深对线程池的理解,相信后续对多线程编程的实践能够更加得心应手。

本文的主要内容有:

1、ThreadPoolExecutor的内部构成

2、线程池的执行机制

3、Future未来对象

ThreadPoolExecutor的内部构成

我们可以结合ThreadPoolExecutor的源码来看下该对象的内部构成:

从源码中可以得出以下结论:

1、内部维持一个任务队列,也就是_work_queue,持有一个SimpleQueue对象,用于存储待执行的任务,所有提交的任务都先添加进入该队列中。

2、内部维持一个线程池,是一个set(),用于控制同时工作的线程集合。工作线程都是Thread对象,负责任务的实际执行。

3、max_workers,用于控制工作线程集合的线程最大个数。默认为CPU核数 + 1,同时限制最大不超过32。

4、通过Future对象实现线程结果及异常的跨线程传递。

线程池的执行机制

线程池的执行流程主要涉及到以下环节:

1、创建线程池:通过ThreadPoolExecutor(max_workers)创建一个线程池。

2、提交任务:通过调用submit()方法提交可调用对象(或者函数)及其参数作为待执行任务,添加至任务队列中。

3、获取工作线程:线程池中的空闲的工作线程会从任务队列中获取任务。

4、执行任务:每个工作线程会调用提交的函数并传递相应的参数。执行结果会异步地封装进Future对象中。

5、处理结果:用户可以通过Future对象获取任务的执行结果、异常信息等。可以使用result()方法等待任务执行完成并获取结果。

6、关闭线程池:任务执行完毕后,可以调用shutdown(wait=True)方法来关闭线程池,不再接受新的任务提交,并等待已提交的任务执行完成再真正关闭。

相应的执行机制,可以参考下面简化的示意图:

Future未来对象

Future对象,也叫作未来对象,用于进行线程执行结果的异步传递。它提供了一种机制来处理尚未完成的操作,允许程序在等待结果时能够有效执行其他任务。

关于Future对象的设计,需要结合源码,稍微展开介绍一下:

从初始化方法中,可以看到Future对象的实现主要涉及到几个关键组件:

1、状态管理:通过_state属性维护当前工作线程的任务执行状态,状态主要有:PENDING、RUNNING、CANCELED、CANCELED_AND_NOTIFIED、FINISHED等。

2、结果的存储:一旦任务完成,工作线程会将相应的结果设置到Future对象中,通过_result属性维持。如果工作线程执行中发生异常,也会将异常信息回写到Future对象中,通过_exception属性维持。

3、回调机制:用户可以注册回调函数,实现任务完成自动执行相应的函数的逻辑。

Future对象支持的操作主要有:

1、result(timeout=None):如果任务已经完成,则返回其结果;如果没有完成,则阻塞等待;如果超时,则抛出TimeoutError异常。

2、exception(timeout=None):如果任务执行完成并且抛出了异常,则返回该异常;否则返回None。

3、done():返回一个布尔值,标识任务是否已经执行完成。

4、cancel():取消一个任务的执行(如果可能的话),如果任务已经开始执行,则无法取消,返回False。

5、add_done_callback(fn):添加回调函数,使得任务完成时,自动调用该函数。

总的来说,正是由于Future对象的设计理念围绕着简化异步操作和提高并发编程的可用性展开。通过提供非阻塞调用、异步处理和回调机制。Future对象使得开发者可以更加方便地管理异步计算的状态和结果。它是实现高效并发执行和任务管理的重要工具,对于需要处理大量异步任务的应用程序尤为关键。

总结

本文围绕着ThreadPoolExecutor和Future对象的源码,深入介绍了相应的内部实现,以及线程池任务的处理全流程。对Future对象的设计理念和基础操作,也做了相应的展开介绍。这些都是理解线程池并发编程的核心,希望您能有所收获。

相关推荐
前端青山16 分钟前
webpack指南
开发语言·前端·javascript·webpack·前端框架
hummhumm19 分钟前
第 10 章 - Go语言字符串操作
java·后端·python·sql·算法·golang·database
chusheng184023 分钟前
Python 正则表达式进阶用法:分组与引用详解
数据库·python·正则表达式
nukix30 分钟前
Mac Java 使用 tesseract 进行 ORC 识别
java·开发语言·macos·orc
XiaoLeisj40 分钟前
【JavaEE初阶 — 多线程】内存可见性问题 & volatile
java·开发语言·java-ee
Lizhihao_1 小时前
JAVA-队列
java·开发语言
denghai邓海1 小时前
红黑树删除之向上调整
python·b+树
HC182580858321 小时前
“倒时差”用英语怎么说?生活英语口语学习柯桥外语培训
学习·生活
励志前端小黑哥1 小时前
有了Miniconda,再也不用担心nodejs、python、go的版本问题了
前端·python
学习路上_write1 小时前
FPGA/Verilog,Quartus环境下if-else语句和case语句RT视图对比/学习记录
单片机·嵌入式硬件·qt·学习·fpga开发·github·硬件工程