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对象的设计理念和基础操作,也做了相应的展开介绍。这些都是理解线程池并发编程的核心,希望您能有所收获。

相关推荐
bohu831 分钟前
sentinel学习笔记1-为什么需要服务降级
笔记·学习·sentinel·滑动窗口
HE10298 分钟前
威尔克斯(Wilks)分布
学习
yayaya15210 分钟前
javaScriptBOM
开发语言·javascript·ecmascript
FBI780980459415 分钟前
API接口在电商行业中的创新应用与趋势
运维·网络·人工智能·爬虫·python
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭17 分钟前
C#都可以找哪些工作?
开发语言·c#
程序员黄同学18 分钟前
如何使用 Flask 框架创建简单的 Web 应用?
前端·python·flask
凡人的AI工具箱39 分钟前
每天40分玩转Django:Django管理界面
开发语言·数据库·后端·python·django
utmhikari44 分钟前
【Python随笔】如何用pyside6开发并部署简单的postman工具
python·postman·pyqt·pyside6·桌面工具
碧水澜庭1 小时前
django中cookie与session的使用
python·django
每天写点bug1 小时前
【go每日一题】:并发任务调度器
开发语言·后端·golang