Python多线程机制

python的多线程机制和构造 Python的多线程机制通过threading模块提供了强大的支持,适用于多种并发编程场景。通过合理使用锁、队列等同步机制,可以有效避免数据竞争和死锁问题。然而,在CPU密集型任务中,GIL的存在可能会限制多线程的性能。因此,在设计多线程程序时,需要根据具体任务类型选择合适的同步策略和优化方法。 阅读详情

开发多线程的应用系统,是在日常的软件开发中经常会遇到的需求。现在的编程语言都为多线程开发提供了很好的支持,无论是通过库的支持还是将多线程机制内建在语言之中。Python也为多线程系统的开发提供了很好的支持。

同样身为动态语言,Ruby也提供了多线程的支持,但是在 Ruby 1.9之前的多线程机制是在语言的实现中模拟了线程及线程调度机制,而并没有使用操作系统本身的线程机制(在以后的描述中,我们称为原生线程)。Ruby 1.9中整合了YARV作为Ruby新的虚拟机,在YARV中,将操作系统的原生线程引入了Ruby。每一个Ruby线程都对是操作系统上的一个线程,在 Ruby内部,维护着一个全局资源锁,一个Ruby线程必须首先获得这个锁,才能成为活动的线程,从而使用Ruby虚拟机的全局资源。

这一切,在Python中早已实现,Python中的线程从一开始就是操作系统的原生线程,而Python虚拟机也同样使用一个全局解释器锁(Global Interpreter Lock,GIL)来互斥线程对Python虚拟机的使用。

15.1  GIL与线程调度

为了理解Python为什么需要Global Interpreter Lock(GIL),考虑这样的情形:假设有两个线程A、B,在两个线程中,都同时保存着对内存中同一对象obj的引用,也就是说,这时 obj->ob_refcnt的值为2。如果A销毁对obj的引用,显然,A将通过Py_DECREF调整obj的引用计数值。我们知 道,Py_DECREF的整个动作可以分为两个部分:

?         --obj->ob_refcnt;

?         if(obj->ob_refcnt == 0) destory object and free memory。

如果A在执行完第一个动作之 后,obj->ob_refcnt的值变为1。不幸的是,恰恰在这个时候,线程调度机制将A挂起,而唤醒了B。更为不幸的是,B同样也开始销毁对 obj的引用。B完成第一个动作之后,obj->ob_refcnt为0,B是一个幸运儿,它没有被线程调度打断,而是顺利地完成了接下来的第二个 动作,将对象销毁,内存释放。好了,现在A又被重新唤醒,可惜现在已经物是人非,obj->ob_refcnt已经被B减少到0,而不是当初的1。 按照约定,傻乎乎的A开始再一次地对已经销毁的对象进行对象销毁和内存释放的动作。这样的结局是什么?只有天知道。

为了支持多线程机制,一个基本的要求就是需要实现不同线程对 共享资源访问的互斥,Python也不例外,这正是引入GIL的根源所在。Python中的GIL是一个非常霸道的互斥实现,正如它的名字所暗示 的,GIL是一个解释器(Interpreter)——为了呼应GIL中的Interpreter,本章中,我们会以解释器来称呼虚拟机——级的互斥机 制,也就是说,在一个线程拥有了解释器的访问权之后,其他的所有线程都必须等待它释放解释器的访问权,即使这些线程的下一条指令并不会互相影响。初看上 去,这样的保护机制粒度太大了,我们似乎只需要将可能被多个线程共享的资源保护起来即可,对于不会被多个线程共享的资源,完全可以不用保护。实际上,在 Python的发展历史中,确实出现过这样的解决方案,但是令人惊奇的,这样的方案在单处理器上的多线程实现的效率上却没有GIL的方案好。所以现在 Python中的多线程机制是在GIL的基础上实现的。

当然,这样的方案也意味着,无论如何,在同一时间,只能有一 个线程能访问Python所提供的API。注意这里的同一时间对于单处理器是毫无意义的,因为单处理器的本质是不可能并行的,但是对于多处理器,情形就完 全不同了,同一时间,确实可以有多个线程独立运行,然而Python的GIL限制了这样的情形,使得多处理器最终退化为单处理器,性能大打折扣。这一点其 实早已被Python社区所认识,也进行了大量的探索。大约在99年的时候,Greg Stein和Mark Hammond两位老兄基于Python 1.5创建了一份去除GIL的branch,但是很不幸,这个分支在很多基准测试上,尤其是单线程操作的测试上,效率只有使用GIL的Python的一半 左右。因为细粒度的锁机制会导致大量的加锁、解锁的操作,而加锁、解锁对于操作系统来说,是一个比较重量级的动作;另一方面,没有了GIL的保护,编写 Python扩展模块的难度大大增加。所以,到目前Python的最新版本2.5为止,GIL仍然是多线程机制的基石,而我们也仍然将视线集中在单处理器 上。实际上,在去年5月份Python 3000的邮件列表上,Python的创造者,Guido,提出了一个比较可行的的解决方案,在多处理器的情况下,完全可以创建多个Python进程,充 分使用多处理器,进程之间通过IPC的方式进行通信。当然,Guido也仅仅是提出了这么一个想法,并没有太多的实现细节透露出来。

图15-1显示了我们对Python的多线程机制所建立的一个粗略的模型。

python多线程机制 - 苏克儿 - 计算机软件技术与理论研讨

图15-1  Python线程机制的粗略模型

从之前的分析中,我们知道,对于Python而言,字节码解 释器是Python的核心所在,所以Python通过GIL来互斥不同线程对解释器的使用。在图15-1中,三个拟人化的线程A,B和C都需要使用解释器 来执行字节码,以完成某种计算,但是在这之前,它们必须获得GIL,因为GIL把守着通往字节码解释器的大门。当某个线程(A)获得了GIL之后,其他的 两个线程(B,C)只能等待A释放GIL之后,然后才能进入解释器,执行一些计算。实际上,Python的GIL背后所保护的不仅仅是Python的解释 器,同样还有Python的C API,在C/C++和Python的混合开发中,在涉及到原生线程和Python线程的相互协作时,也需要通过GIL进行互斥。关于这一点,我们将在后 面详细阐述。

那么A在何时释放GIL呢?如果等到A使用完了解释器之后才释放GIL,这也就意味着,并行的计算退化为了串行的计算,要这样的多线程机制有什么意义呢?所有毫无疑问的,Python拥有一套线程的调度机制。

对于线程调度机制而言,同操作系统的进程调度一样,最关键的是要解决两个问题:

?        在何时挂起当前线程,选择处于等待状态的下一个线程?

?        在众多的处于等待状态的候选线程中,选择激活哪一个线程?

在Python的多线程机制中,这两个问题是分别由不同的层 次解决的。对于何时进行线程调度的问题,是由Python自身决定的。考虑一下操作系统是如何进行进程的切换的,当一个进程执行了一段时间之后,发生了时 钟中断,操作系统响应时钟中断,并在这时开始进行进程的调度。同样,Python中也是通过软件模拟了这样的时钟中断,来激活线程的调度。我们知 道,Python字节码解释器的工作原理是按照指令的顺序一条一条地顺序执行,Python内部维护着一个数值,这个数值就是Python内部的时钟,如 果这个数值为N,则意味着Python在执行了N条指令以后应该立即启动线程调度机制,图15-2显示了如何获得Python内部默认设定的这个值。

python多线程机制 - 苏克儿 - 计算机软件技术与理论研讨

图15-2  Python2.5内部的“时钟中断”间隔值

图15-2显示的结果意味着,在当前的2.5 中,Python的默认行为是在执行了100条指令以后启动线程调度机制。实际上,这个值不仅仅是用来进行线程调度的,在内部,Python也使用它来检 查是否有异步的事件(event)发生,需要处理。我们可以通过sys.setc- heckinterval()来调节这个值。

现在我们知道了,Python控制着什么时候进行线程调度, 当一个线程获得了访问Python解释器的所必须的GIL并进入Python解释器后,Python内部的监测机制就开始启动,当这个线程执行了100条 指令之后,Python解释器将强制挂起当前线程,开始切换到下一个处于等待状态的进程。

那么究竟Python会在众多的等待线程中选择哪一个幸运儿 呢?答案是,不知道。没错,对于这个问题,Python完全没有插手,而是交给了底层的操作系统来解决。也就是说,Python借用了底层操作系统所提供 的线程调度机制来决定下一个进入Python解释器的线程究竟是谁。

这一点至关重要,这就意味着Python中的线程实际上就是 操作系统所支持的原生线程,而并非如坊间所流传的那样:Python的线程并非原生线程,而是模拟出来的。Python中的多线程机制正是建立在操作系统 的原生线程的基础之上,对应不同的操作系统,有不同的实现,然而最终,在各不相同的原生线程的基础之上,Python提供了一套统一的抽象机制,给 Python的使用者一个非常简单而方便的多线程工具箱,这就是Python中的两个module:thread以及在其之上的threading。

Python多线程与锁机制的深入探讨 本文将深入探讨Python中的多线程编程及其与锁机制的协同工作。通过分析使用with语句结合Lock、RLock、Semaphore和Condition等同步原语的示例,我们将理解多线程环境下的资源共享和同步问题。文章还包含对守护线程继承、多线程访问临界区的分析以及线程间的通信和协作机制,旨在为读者提供一个全面的多线程编程视角。 阅读详情

相关推荐

单视图几何Vanish Point(消失点/灭点)计算方法——Robert_T_Collins(罗伯特·柯林斯)算法

单视图几何Vanish Point(消失点/灭点)计算方法——Robert_T_Collins(罗伯特·柯林斯)算法

beyond951的博客 7332

Python多线程详解

关于Python多线程的详细解读

ifhuke的博客 2万+

MATLAB实战:手把手教你搭建构网逆变器同步稳定性仿真模型(附避坑指南)

本文详细介绍了如何在MATLAB/Simulink平台上搭建构网逆变器同步稳定性仿真模型,涵盖从基础模块配置到虚拟同步机控制实现的完整流程。针对电力电子工程师常见的控制参数整定困难、仿真结果偏差等问题,提供了LCL滤波器谐振抑制、虚拟惯量优化等关键技术解决方案,并附有避坑指南和工程实践技巧,助力研究者高效完成仿真建模。

weixin_29051193的博客 295

Python学习系列之多线程

一、多线程定义       进程是由若干线程组成的,一个进程至少有一个线程,叫主线程。 多线程类似于同时执行多个不同程序,多线程运行有如下优点: 使用线程可以把占据长时间的程序中的任务放到后台去处理,不会出现界面卡顿的情况。 用户界面更加友好,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度。 程序的运行速度可能加快。 在一些等待的任务实现上如用户输入、...

answer3lin的博客 1万+

天线学习笔记——HFSS简单阵列天线

在HFSS15.0版本中使用 Radiation --> Antenna Array Setup 设置天线阵列的参数时的设计列表如下: 值得注意的是,在该版本中所定义的是:第一个阵元的位置坐标(First Cell Position)、阵元之间的间距(Directions)和阵元的数量(Number of Cells) 这些参数。 在ANSYS中的HFSS仿真中定义天线阵列如下: 与老版本不同的是:中心点坐标(Center Position)和布局设置(Layout Setting)。在布局设置中

Ethan的博客 1万+

SoC芯片时钟树优化实战:如何用分段CTS解决DDRPHY与Memory Controller的时序难题

本文深入探讨了SoC芯片时钟树优化中的分段CTS技术,重点解决DDRPHY与Memory Controller之间的时序难题。通过分析多域时钟架构的复杂性,提出三级分段CTS策略,并结合28nm移动SoC实战案例,展示如何通过Guide Buffer插入和本地段重构实现72%的跨域偏差改善。文章还涵盖5nm以下工艺的线阻变异、热梯度效应等特殊考量,为数字IC设计提供时钟树综合的高阶解决方案。

kkk56的博客 904

由浅入深掌握Python多线程原理与编程步骤

本文以实例代码形式,讲解多线程 multithreading,,全局锁GIL原理,多线程编程基本步骤 ,threading模块 Thread 属性、方法、公共函数,以函数式,类的方式创建线程,线程生命周期管理,如何处理子线程异常 thread exception,最后讲解了高并发线程池ThreadPoolExecutor异步编程技术

Python技术探索 9461

分析国外几款主流蜜罐产品看欺骗诱捕技术的应用脉络

网络安全的本质是攻防对抗,更本质的其实是人与人心智与技术的全面较量。 欺骗诱捕技术作为攻防对抗技术中比较特殊的技术,能够使防守方更多掌握对抗中的主动权,诱导攻击,迫使攻击者耗费精力的同时,留下丰富的攻击信息。究其本质,欺骗诱捕技术更深层次考验的不止是技术的能力,还有对于攻击者作为人的理解。 国外主流蜜罐产品分析 根据MarketsandMarkets《欺骗技术市场规模、份额和2021年全球市场预测》中提到的欺骗诱捕技术全球主要供应商及产品,我们分析了几款国外主流的蜜罐产品,希望更清晰看到欺骗诱捕技术应

cdyunaq的博客 1306

Python教程:一文掌握Python多线程(很详细)

多线程是指在同一进程内同时运行多个线程,每个线程执行不同的任务,实现并发执行。每个线程都有自己的执行路径,可以独立运行和调度,共享进程的资源。

旦莫的博客 3万+

逆向分析踩坑记:当Frida在x86模拟器上‘看不见’ARM的so文件时,我们该如何手动定位与验证?

本文探讨了在x86模拟器上使用Frida进行逆向分析时,无法检测到ARM架构so文件的解决方案。通过分析内存映射、Frida的视觉盲区及手动定位技术,提供了兼容层、混合调试和原生ARM环境三种实用方案,帮助逆向工程师突破工具限制,实现精准定位与验证。

weixin_27697385的博客 221

程序员实战:DINOv3 权重文件下载与本地化部署全流程指南

Meta开源的DINOv3视觉大模型凭借70亿参数和17亿图像训练,在语义分割、目标检测等任务表现优异。本文详解预训练权重的获取渠道、校验方法和加载实践。开发者可通过HuggingFace或GitHub获取不同版本权重,包括针对服务器端的ViT系列和边缘设备的ConvNeXt系列。文章提供MD5校验代码确保文件完整性,并给出PyTorch和Transformers两种加载方式。特别强调7B模型需16GB GPU内存,建议根据硬件条件选择合适版本,如边缘设备使用ConvNeXt-Tiny。最后指出DINOv3

xiugou3365的博客 5901

python多线程机制

开发多线程的应用系统,是在日常的软件开发中经常会遇到的需求。现在的编程语言都为多线程开发提供了很好的支持,无论是通过库的支持还是将多线程机制内建在语言之中。Python也为多线程系统的开发提供了很好的支持。 同样身为动态语言,Ruby也提供了多线程的支持,但是在Ruby1.9之前的多线程机制是在语言的实现中模拟了线程及线程调度机制,而并没有使用操作系统本身的线程机制(在以后的描述中,我们称为原生

回忆的往昔 623

openssl+SM2开发实例一(含源码)

是中国国家密码管理局(CNCA)颁布的椭圆曲线密码算法标准,属于非对称加密算法。它基于椭圆曲线离散对数问题,提供了安全可靠的数字签名、密钥交换和公钥加密等功能。SM2被设计为适用于各种场景下的密码学应用,包括数字证书、数据加密、数字签名、身份认证等。SM2是一种非对称加密算法,意味着它使用两个密钥:公钥和私钥。公钥用于加密数据和验证签名,而私钥用于解密数据和生成签名。SM2基于椭圆曲线密码学(Elliptic Curve Cryptography,ECC),使用椭圆曲线上的点运算来实现加密和签名操作。

N阶二进制的博客 7986

Python中的多线程锁机制

本文介绍了Python中的多线程锁机制及其应用。主要内容包括:1)6种主要锁类型(Lock、RLock、Semaphore、Condition、Event、Barrier)的特点和使用场景;2)每种锁的代码示例演示;3)两个实际应用案例(线程安全计数器和生产者-消费者模式);4)多线程编程的最佳实践建议。文章强调,虽然Python有GIL限制,但在I/O密集型任务和资源共享场景中,合理使用锁机制对保证线程安全至关重要。

yuanpan的专栏 1119

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Python 的多线程机制

Python 通过 threading 模块支持多线程,但由于 GIL 限制,其多线程在 CPU 密集型任务中无法利用多核优势,但在 IO 密集型任务中仍能提升效率。核心机制包括 threading 模块的基础线程操作和线程同步工具,以及 ThreadPoolExecutor 线程池管理。asyncio.to_thread() 是异步框架中对多线程的封装,并非替代多线程机制。对于 CPU 密集型任务,建议使用多进程或异步框架。本文还介绍了多线程的典型应用场景和高级用法。

servepeople的博客 429

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

python多线程的机制与使用

python的多线程机制与使用进程和线程一、进程二、线程三、总结四、为什么要使用多线程五、并发和并行六、Python的进程和线程的区别七、实例实现多线程八、自定义的方式来产生线程 进程和线程 一、进程 进程是程序的分配资源的最小单元;一个程序可以有多个进程,但只有一个主进程;进程由程序、数据集、控制器三部分组成。 二、线程 线程是程序最小的执行单元;一个进程可以有多个线程,但是只有一个主线程;线程...

paul0926的博客 417

python中多线程调度机制以及GIL

总结下python中线程调度机制. 对于线程调度机制而言,同操作系统的进程调度一样,最关键是要解决两个问题: 1.在何时选择挂起当前线程,并选择处于等待的先一个线程呢? 2.在众多等待的线程中,选择哪一个作为激活线程呢? 在python多线程机制中,这个两个问题是有两个层次解决的。 如,进程间的切换,当发生了时钟中断,操作系统响应时钟中断,并在这个时候开始进程的调

职场里拉开差距的不是知识,而是认知! 5364

python多线程机制深入理解

今天要跟大家一起来学习一下Python的多线程机制。有两个原因,其一是自己在学习中经常会使用到多线程,其二当然是自己对Python中的多线程并不是很了解。那么,今天和大家一起了解下~ Python多线程机制 开发多线程的应用系统,是在日常开发中经常会遇到的需求。同时,Python也为多线程系统的开发提供了很好的支持。 大家应该都知道,Python多线程机制是在GIL(Global Interp...

shaowei的博客 3313

python多线程调度_Python多线程机制

今天要跟大家一起来学习一下Python的多线程机制。有两个原因,其一是自己在学习中经常会使用到多线程,其二当然是自己对Python中的多线程并不是很了解。那么,今天和大家一起了解下~Python多线程机制开发多线程的应用系统,是在日常开发中经常会遇到的需求。同时,Python也为多线程系统的开发提供了很好的支持。大家应该都知道,Python多线程机制是在GIL(Global Interpreter...

weixin_39669265的博客 335

python的多线程机制_python多线程锁机制

前面说到了python多线程是为了让一个程序同时干两件或者多件事情,达到多任务功能。那么问题又来了,同时干多件事情的时候,多件事情之间会不会有影响呢?比如A线程要修改num=1这个变量,B线程也要修改num=1这个变量,那么这个时候到底听谁的?再举个取钱的例子(貌似别人讲线程的时候也喜欢用取钱这个例子),假如小明的银行卡里有10000元,他在ATM机上取出1000元(A线程)的同时也通过从银行卡转...

weixin_39801714的博客 117

Python多线程之“锁机制”

Python多线程之“锁机制”锁(Lock)机制简述锁(Lock)机制使用为什么要使用锁? 锁(Lock)机制简述 锁这个字已经顾名思义了。有A和B两个线程,A和B中的程序都加了同一个锁对象,当线程A率先执行到lock.acquire(),线程B只能在A释放锁lock.release()后才能运行自身的lock.acquire()。 锁(Lock)机制使用 以下代码为如何获取锁,释放锁,获取锁lo...

未知艺术家的博客 543

Python 单线程与多线程的底层机制

Python 的单线程与多线程机制虽然受到 GIL 的限制,但通过合理的设计和优化,仍然可以构建出高效的应用程序。理解 GIL 的工作原理以及如何绕过它的限制,是成为一名优秀 Python 开发者的必备技能。无论是单线程还是多线程,最终的目标都是为了让程序更加高效、稳定和易于维护。本文介绍了 Python 单线程与多线程的底层机制,希望对你有所帮助!如果你有任何疑问或建议,请随时留言交流。```

2501_91173181的博客 1491

python多线程之Event机制笔记

这是熟悉python 多线程 event机制的学习笔记

wyz0923的博客 680
上一篇: Linux线程通信
下一篇: Python虚拟机实现
celte
博客等级 码龄15年 40粉丝 74原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值