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

相关推荐
jeo陽4 分钟前
04-循环实战:素数、最大公约数、级数求和与枚举法
c语言·开发语言·数据结构
暖核23 分钟前
kubeadm 集群运维:Worker 节点下线删除、整套集群销毁重建指南
运维·开发语言·php
Awh-25 分钟前
ARM 裸机开发 DAY11 学习笔记
arm开发·笔记·学习
尼给路达哟32 分钟前
node(koa)和python(fastapi)面试
python·面试·fastapi
tachibana21 小时前
Go 语言里的 Context 是什么?
开发语言·后端·golang·go·语言
天桥下的卖艺者1 小时前
R语言使用ggcube包轻松绘制文章中的各类3D图形
开发语言·3d·r语言
曲径海盗2 小时前
【Python 学习第 32 天】字符串基础
python·学习笔记·编程入门
田里的水稻2 小时前
PyTorch_torchvision---数据集下载\TensorBoard可视化
人工智能·pytorch·python·深度学习·机器学习
程序员正茂2 小时前
Win11使用自定义训练集训练ncnn模型
python·yolo·图像识别·移动端·ncnn
zwd20052 小时前
Manim 画布尺寸与像素换算详解:frame_width、frame_height、pixel_width 和画质参数(0.21.0 实测)
python·分辨率·manim·数学动画·frame_width·manim教程