2016 - 2024

感恩一路有你

python3.10彻底解决多线程锁 python dict是线程安全的吗?

浏览量:4119 时间:2023-07-12 20:42:35 作者:采采

python dict是线程安全的吗?

list的任何操作的行为都应该是安全的,比如代码lst [] lst [0] 1的Python虚拟机执行的对应字节码序列是:load _ const 1(1)load _ fast 0(lst)load _ const 2(0)STORE _ SUBSCR。存储数据的操作发生在store _ subscr字节码中。这里需要明确的是,Python虚拟机的线程调度,或者说中断机制,是基于字节码的,也就是说一个字节码操作可以认为是一个原子操作,所以STORE _ SUBSCR即使在多线程环境下也不会被中断,并且可以成功完成,所以list的任何操作的行为都是确定的。

Python多进程和多线程是鸡肋嘛?

GIL的存在一直备受争议,这使得Python程序无法真正利用现代操作系统的多进程特性。需要注意的是,I/O图形处理和NumPy数学计算等耗时的操作都发生在GIL之外,基本上不受影响。真正受影响的是Python字节码的执行,GIL会导致性能瓶颈。简而言之,只有当纯Python用于CPU密集型多线程时,GIL才会成为问题。

什么是GIL?Python s代码执行由Python虚拟机控制(也叫解释器主循环,CPython版本)。Python最初被设计成只有一个线程在解释器主循环中运行。也就是说,每个CPU在任何时候都只有一个线程在解释器中运行。对Python虚拟机的访问由全局解释锁GIL控制,它控制一次只能运行一个线程。-单核CPU下的多线程其实是并发的,不是并行的。

并发和并行的区别

并发性:两个或多个事件在同一时间间隔内发生,或者交替做不同的事件,或者交替执行不同的代码块的能力。并行性:两个或多个事件同时发生,或者同时执行不同事件,或者同时执行不同代码块的能力。

并发和并行的含义

并发和并行都可以处理 "多任务 ",两者的主要区别在于多任务是否 "同时进行 "。但是涉及到任务分解(有顺序依赖耦合度高的任务不能并行)、任务操作(互斥、加锁、共享等。),以及结果合并。

Python中的多线程在Python多线程下,每个线程的执行模式如下:

有两种机制可以让GIL切换到这个线程来执行正在运行的代码:指定数量的字节码指令(100),15ms的固定时间,线程主动让步控制,以及将线程设置为睡眠状态。松开GIL,再次重复上述步骤。在Python2中,解释器解释执行任何Python代码时,都需要先获得这个锁(只有一个获得了GIL的线程在同时运行,其他所有线程都在等待GIL释放),遇到I/O操作时,这个锁就会被释放。如果是没有I/O操作的纯计算程序,解释器会每100次操作释放一次锁,让其他线程有机会执行(这个数字可以通过调整)。正是这样的设定,多线程CPU密集型计算显得很鸡肋,下面就说说为什么。

在python3中,GIL不使用滴答计数(100次,释放GIL),而是使用定时器(执行时间达到15ms阈值后,当前线程释放GIL),使得执行次数更多,释放次数更少,对CPU密集型程序更友好,但仍然没有解决GIL一次只能执行一个线程的问题,所以效率还是不尽如人意。

Python s多线程一个鸡肋?CPU密集型(各种循环处理,计数等。),在这种情况下,滴答数很快就会达到阈值,然后触发GIL的释放和重新竞争(多线程来回切换需要资源),所以python中的多线程对CPU密集型代码并不友好,会触发相当频繁的线程切换。

IO密集型(文件处理、网络爬虫等。),多线程可以有效提高效率(如果单线程下有IO操作,就会等待IO,造成不必要的时间浪费,而开启多线程可以在线程A等待的同时自动切换到线程B,不会浪费CPU资源,从而提高程序执行效率。一个线程从GIL获得一个消息,然后等待返回消息(阻塞),Python在这个时候释放GIL。其他线程得到GIL发送的消息,然后等待返回消息(阻塞)........................................................................................................................................................所以python 的多线程对IO密集型代码很友好。

结论是什么?I/O密集型使用多线程并发执行提高效率,计算密集型使用多处理并行执行提高效率。通常程序中既包含IO操作,又包含计算操作,所以这种情况下,在开始并发任务之前,可以先测试一下,测试一下多线程多进程哪种方法效率高。

请注意:多核多线程比单核多线程差。多核多进程下,CPU1释放GIL后,其他CPU上的线程会竞争,但GIL可能马上被CPU1拿走,CPU2释放GIL后...其他CPU上被唤醒的线程将被唤醒。等待切换时间后会进入待调度状态,会造成线程抖动,导致效率降低。

多线程下的CPU密集型计算并非不可救药。ctypes可以绕过GIL,让py直接调用C动态库的任何导出函数。我们要做的就是用C/C把关键部分写成Python扩展,而且ctypes会在调用C函数之前释放GIL。

同时可以了解下一个进程,也就是微线程。

协成最大的优势就是极高的执行效率。因为子程序切换不是线程切换,而是由程序本身控制,所以没有线程切换的开销。与多线程相比,线程越多,协程的性能优势就越明显。

第二个好处是不需要多线程锁机制,因为只有一个线程,不存在同时写变量的。在协调过程中,只需要判断状态,不需要锁定共享资源,因此执行效率远高于多线程。

因为进程是一个线程执行的,如何使用多核CPU?最简单的方法就是多进程协调,既充分利用了多核,又充分发挥了协调的高效率,可以获得极高的性能。

线程 GIL 多线程 Python 代码

版权声明:本文内容由互联网用户自发贡献,本站不承担相关法律责任.如有侵权/违法内容,本站将立刻删除。