精华内容
下载资源
问答
  • Python 全局解释器锁

    2019-06-09 16:43:38
    GIL:Global Interpreter Lock,意思就是全局解释器锁,这个不是python语言的特征,而是Cpython解释器里引入的一个概念,而在其他的语言编写的解释器里就没有这个GIL例如:Jython,Pypy 为什么会有gil?: 随着电脑...

             GIL:Global Interpreter Lock,意思就是全局解释器锁,这个不是python语言的特征,而是Cpython解释器里引入的一个概念,而在其他的语言编写的解释器里就没有这个GIL例如:Jython,Pypy

    为什么会有gil?:

           随着电脑多核cpu的出现核cpu频率的提升,为了充分利用多核处理器,进行多线程的编程方式更为普及,随之而来的困难是线程之间数据的一致性和状态同步,而python也利用了多核,所以也逃不开这个困难,为了解决这个数据不能同步的问题,设计了gil全局解释器锁。

     

    在Cpython解释器中,当我们的python代码有一个线程开始访问解释器的时候,GIL会把这个大锁给锁上,此时此刻其他的线程只能干等着,无法对解释器的资源进行访问,这一点就跟我们的互斥锁相似。而只是这个过程发生在我们的Cpython中,同时也需要等这个线程分配的时间到了,这个线程把gil释放掉,类似我们互斥锁的lock.release()一样,另外的线程才开始跑起来,说白了,这无疑也是一个单线程。
    --------------------- 

    作者:lafeilong 
    来源:CSDN 
    原文:https://blog.csdn.net/feilzhang/article/details/80294572 
    版权声明:本文为博主原创文章,转载请附上博文链接!

    展开全文
  • Python全局解释器锁

    2018-03-14 21:25:00
    超过十年以上,没有比解释器全局锁(GIL)让Python新手和专家更有挫折感或者更有好奇心。 Python的底层 要理解GIL的含义,我们需要从Python的基础讲起。像C++这样的语言是编译型语言,所谓编译型语言,是指程序...

    超过十年以上,没有比解释器全局锁(GIL)让Python新手和专家更有挫折感或者更有好奇心。

       Python的底层

        要理解GIL的含义,我们需要从Python的基础讲起。像C++这样的语言是编译型语言,所谓编译型语言,是指程序输入到编译器,编译器再根据语言的语法进行解析,然后翻译成语言独立的中间表示,最终链接成具有高度优化的机器码的可执行程序。编译器之所以可以深层次的对代码进行优化,是因为它可以看到整个程序(或者一大块独立的部分)。这使得它可以对不同的语言指令之间的交互进行推理,从而给出更有效的优化手段。   

        与此相反,Python是解释型语言。程序被输入到解释器来运行。解释器在程序执行之前对其并不了解;它所知道的只是Python的规则,以及在执行过程中怎样去动态的应用这些规则。它也有一些优化,但是这基本上只是另一个级别的优化。由于解释器没法很好的对程序进行推导,Python的大部分优化其实是解释器自身的优化。更快的解释器自然意味着程序的运行也能“免费”的更快。也就是说,解释器优化后,Python程序不用做修改就可以享受优化后的好处。

        这一点很重要,让我们再强调一下。如果其他条件不变,Python程序的执行速度直接与解释器的“速度”相关。不管你怎样优化自己的程序,你的程序的执行速度还是依赖于解释器执行你的程序的效率。这就很明显的解释了为什么我们需要对优化Python解释器做这么多的工作了。对于Python程序员来说,这恐怕是与免费午餐最接近的了。

        免费午餐结束了

        还是没有结束?摩尔定律给出了硬件速度会按照确定的时间周期增长,与此同时,整整一代程序员学会了如何编码。如果一个人写了比较慢的代码,最简单的结果通常是更快的处理器去等待代码的执行。显然,摩尔定律仍然是正确的,并且还会在很长一段时间生效,不过它提及的方式有了根本的变化。并非是时钟频率增长到一个高不可攀的速度,而是通过多核来利用晶体管密度提高带来的好处。在新处理器上运行的程序要想充分利用其性能,必须按照并发方式进行重写。

        大部分开发者听到“并发”通常会立刻想到多线程的程序。目前来说,多线程执行还是利用多核系统最常用的方式。尽管多线程编程大大好于“顺序”编程,不过即便是仔细的程序员也没法在代码中将并发性做到最好。编程语言在这方面应该做的更好,大部分应用广泛的现代编程语言都会支持多线程编程

        意外的事实

        现在我们来看一下问题的症结所在。要想利用多核系统,Python必须支持多线程运行。作为解释型语言Python的解释器必须做到既安全又高效。我们都知道多线程编程会遇到的问题。解释器要留意的是避免在不同的线程操作内部共享的数据。同时它还要保证在管理用户线程时保证总是有最大化的计算资源。

        那么,不同线程同时访问时,数据的保护机制是怎样的呢?答案是解释器全局锁。从名字上看能告诉我们很多东西,很显然,这是一个加在解释器上的全局(从解释器的角度看)锁(从互斥或者类似角度看)。这种方式当然很安全,但是它有一层隐含的意思(Python初学者需要了解这个):对于任何Python程序,不管有多少的处理器,任何时候都总是只有一个线程在执行

        许多人都是偶然发现这个事实的。网上的很多讨论组和留言板都充斥着来自Python初学者和专家的类似这样的问题——”为什么我全新的多线程Python程序运行得比其只有一个线程的时候还要慢?“许多人在问这个问题时还是非常犯晕的,因为显然一个具有两个线程的程序要比其只有一个线程时要快(假设该程序确实是可并行的)。事实上,这个问题被问得如此频繁以至于Python的专家们精心制作了一个标准答案:”不要使用多线程,请使用多进程。“但这个答案比那个问题更加让人困惑。难道我不能在Python中使用多线程?在Python这样流行的一个语言中使用多线程究竟是有多糟糕,连专家都建议不要使用。难道我真的漏掉了一些东西?

        很遗憾,没有任何东西被漏掉。由于Python解释器的设计,使用多线程以提高性能应该算是一个困难的任务。在最坏的情况下,它将会降低(有时很明显)你的程序的运行速度。一个计算机科学与技术专业的大学生新手可能会告诉你当多个线程都在竞争一个共享资源时将会发生什么。结果通常不会非常理想。很多情况下多线程都能很好地工作,可能对于解释器的实现和内核开发人员来说,没有关于Python多线程性能的过多抱怨

        现在该怎么办?惊慌?

        那么,这又能怎样?问题解决了吗?难道我们作为Python开发人员就意味着要放弃使用多线程来探索并行的想法了?为什么无论怎样,GIL需要保证只有一个线程在某一时刻处于运行中?难道不可以添加细粒度的锁来阻止多个独立对象的同时访问?并且为什么之前没有人去尝试过类似的事情?

        这些实用的问题有着十分有趣的回答。GIL对诸如当前线程状态和为垃圾回收而用的堆分配对象这样的东西的访问提供着保护。然而,这对Python语言来说没什么特殊的,它需要使用一个GIL。这是该实现的一种典型产物。现在也有其它的Python解释器(和编译器)并不使用GIL。虽然,对于CPython来说,自其出现以来已经有很多不使用GIL的解释器

        那么为什么不抛弃GIL呢?许多人也许不知道,在1999年,针对Python 1.5,一个经常被提到但却不怎么理解的“free threading”补丁已经尝试实现了这个想法,该补丁来自Greg Stein。在这个补丁中,GIL被完全的移除,且用细粒度的锁来代替。然而,GIL的移除给单线程程序的执行速度带来了一定的代价。当用单线程执行时,速度大约降低了40%。使用两个线程展示出了在速度上的提高,但除了这个提高,这个收益并没有随着核数的增加而线性增长。由于执行速度的降低,这一补丁被拒绝了,并且几乎被人遗忘。

        移除GIL非常困难,让我们去购物吧!

        译者注:XXX is hard. Let's go shopping!在英语中类似于中文的咆哮体。其隐含意思为想成功完成某件事情非常困难,我们去直接寻找第三方的产品替代吧。)

        不过,“free threading”这个补丁是有启发性意义的,其证明了一个关于Python解释器的基本要点:移除GIL是非常困难的。由于该补丁发布时所处的年代,解释器变得依赖更多的全局状态,这使得想要移除当今的GIL变得更加困难。值得一提的是,也正是因为这个原因,许多人对于尝试移除GIL变得更加有兴趣。困难的问题往往很有趣。

        但是这可能有点被误导了。让我们考虑一下:如果我们有了一个神奇的补丁,其移除了GIL,并且没有对单线程的Python代码产生性能上的下降,那么什么事情将会发生?我们将会获得我们一直想要的:一个线程API可能会同时利用所有的处理器。那么现在,我们已经获得了我们希望的,但这确实是一个好事吗?

        基于线程的编程毫无疑问是困难的。每当某个人觉得他了解关于线程是如何工作的一切的时候,总是会悄无声息的出现一些新的问题。因为在这方面想要得到正确合理的一致性真的是太难了,因此有一些非常知名的语言设计者和研究者已经总结得出了一些线程模型。就像某个写过多线程应用的人可以告诉你的一样,不管是多线程应用的开发还是调试都会比单线程的应用难上数倍。程序员通常所具有的顺序执行的思维模恰恰就是与并行执行模式不相匹配。GIL的出现无意中帮助了开发者免于陷入困境。在使用多线程时仍然需要同步原语的情况下,GIL事实上帮助我们保持不同线程之间数据一致性问题

        那么现在看起来讨论Python最难得问题是有点问错了问题。我们有非常好的理由来说明为什么Python专家推荐我们使用多进程代替多线程,而不是去试图隐藏Python线程实现的不足。更进一步,我们鼓励开发者使用更安全更直接的方式实现并发模型,同时保留使用多线程进行开发除非你觉的真的非常必要的话。对于大多数人来说什么是最好的并行编程模型可能并不是十分清楚。但是目前我们清楚的是多线程的方式可能并不是最好的

        至于GIL,不要认为它在那的存在就是静态的和未经分析过的。Antoine Pitrou 在Python 3.2中实现了一个新的GIL,并且带着一些积极的结果。这是自1992年以来,GIL的一次最主要改变。这个改变非常巨大,很难在这里解释清楚,但是从一个更高层次的角度来说,旧的GIL通过对Python指令进行计数来确定何时放弃GIL。这样做的结果就是,单条Python指令将会包含大量的工作,即它们并没有被1:1的翻译成机器指令。在新的GIL实现中,用一个固定的超时时间来指示当前的线程以放弃这个锁。在当前线程保持这个锁,且当第二个线程请求这个锁的时候,当前线程就会在5ms后被强制释放掉这个锁(这就是说,当前线程每5ms就要检查其是否需要释放这个锁)。当任务是可行的时候,这会使得线程间的切换更加可预测。

        然而,这并不是一个完美的改变。对于在各种类型的任务上有效利用GIL这个领域里,最活跃的研究者可能就是David Beazley了。除了对Python 3.2之前的GIL研究最深入,他还研究了这个最新的GIL实现,并且发现了很多有趣的程序方案。对于这些程序,即使是新的GIL实现,其表现也相当糟糕。他目前仍然通过一些实际的研究和发布一些实验结果来引领并推进着有关GIL的讨论。

        不管某一个人对Python的GIL感觉如何,它仍然是Python语言里最困难的技术挑战。想要理解它的实现需要对操作系统设计、多线程编程、C语言、解释器设计和CPython解释器的实现有着非常彻底的理解。单是这些所需准备的就妨碍了很多开发者去更彻底的研究GIL。虽然如此,并没有迹象表明GIL在不久以后的任何一段时间内会远离我们。目前,它将继续给那些新接触Python,并且与此同时又对解决非常困难的技术问题感兴趣的人带来困惑和惊喜。

        以上内容是基于我目前对Python解释器所做出的研究而写。虽然我还希望写一些有关解释器的其它方面内容,但是没有任何一个比全局解释器锁(GIL)更为人所知。虽然我认为这里有些内容是不准确的,但是这些技术上的细节与CPython的很多资源条目是不同的。如果你发现了不准确的内容,请及时告知我,这样我就会尽快对其进行改正。(本文来自:http://www.oschina.net/translate/pythons-hardest-problem)

    转载于:https://www.cnblogs.com/AmilyWilly/p/8570246.html

    展开全文
  • python gil全局锁The Python Global Interpreter Lock or GIL, in simple words, is a mutex (or a lock) that allows only one thread to hold the control of ... 简而言之,Python全局解释器锁或GIL是一种互斥锁...

    python gil全局锁

    The Python Global Interpreter Lock or GIL, in simple words, is a mutex (or a lock) that allows only one thread to hold the control of the Python interpreter.

    简而言之,Python全局解释器锁或GIL是一种互斥锁(或锁),仅允许一个线程持有Python解释器的控制权。

    This means that only one thread can be in a state of execution at any point in time. The impact of the GIL isn’t visible to developers who execute single-threaded programs, but it can be a performance bottleneck in CPU-bound and multi-threaded code.

    这意味着在任何时间点只有一个线程可以处于执行状态。 对于执行单线程程序的开发人员而言,GIL的影响并不明显,但它可能是CPU绑定和多线程代码的性能瓶颈。

    Since the GIL allows only one thread to execute at a time even in a multi-threaded architecture with more than one CPU core, the GIL has gained a reputation as an “infamous” feature of Python.

    由于即使在具有多个CPU内核的多线程体系结构中,GIL一次一次只允许执行一个线程,因此GIL被誉为Python的“臭名昭著”功能。

    In this article you’ll learn how the GIL affects the performance of your Python programs, and how you can mitigate the impact it might have on your code.

    在本文中,您将学习GIL如何影响Python程序的性能,以及如何减轻GIL对代码的影响。

    GIL为Python解决了什么问题? (What problem did the GIL solve for Python?)

    Python uses reference counting for memory management. It means that objects created in Python have a reference count variable that keeps track of the number of references that point to the object. When this count reaches zero, the memory occupied by the object is released.

    Python使用引用计数进行内存管理。 这意味着用Python创建的对象具有引用计数变量,该变量跟踪指向该对象的引用数。 当此计数达到零时,将释放对象占用的内存。

    Let’s take a look at a brief code example to demonstrate how reference counting works:

    让我们看一个简短的代码示例,以演示引用计数的工作原理:

     >>> >>>  import import sys
    sys
    >>> >>>  a a = = []
    []
    >>> >>>  b b = = a
    a
    >>> >>>  syssys .. getrefcountgetrefcount (( aa )
    )
    3
    3
    

    In the above example, the reference count for the empty list object [] was 3. The list object was referenced by a, b and the argument passed to sys.getrefcount().

    在上面的示例中,空列表对象[]的引用计数为3。列表对象由ab引用,并且参数传递给sys.getrefcount()

    Back to the GIL:

    回到GIL:

    The problem was that this reference count variable needed protection from race conditions where two threads increase or decrease its value simultaneously. If this happens, it can cause either leaked memory that is never released or, even worse, incorrectly release the memory while a reference to that object still exists. This can can cause crashes or other “weird” bugs in your Python programs.

    问题在于该引用计数变量需要保护,以防止两个线程同时增加或减少其值的竞争条件。 如果发生这种情况,则可能导致从未释放的内存泄漏,或者更糟糕的是,在仍然存在对该对象的引用的情况下,错误地释放了内存。 这可能会导致崩溃或Python程序中的其他“怪异”错误。

    This reference count variable can be kept safe by adding locks to all data structures that are shared across threads so that they are not modified inconsistently.

    通过将锁添加到所有在线程之间共享的数据结构中,以便不被不一致地修改,可以保持此引用计数变量的安全。

    But adding a lock to each object or groups of objects means multiple locks will exist which can cause another problem—Deadlocks (deadlocks can only happen if there is more than one lock). Another side effect would be decreased performance caused by the repeated acquisition and release of locks.

    但是,将锁添加到每个对象或一组对象意味着存在多个锁,这可能会导致另一个问题-死锁(只有在有多个锁的情况下才会发生死锁)。 另一个副作用是由于重复获取和释放锁而导致性能降低。

    The GIL is a single lock on the interpreter itself which adds a rule that execution of any Python bytecode requires acquiring the interpreter lock. This prevents deadlocks (as there is only one lock) and doesn’t introduce much performance overhead. But it effectively makes any CPU-bound Python program single-threaded.

    GIL是解释器本身的单个锁,它添加了一个规则,即任何Python字节码的执行都需要获取解释器锁。 这样可以防止死锁(因为只有一个锁)并且不会带来太多的性能开销。 但这实际上使所有受CPU约束的Python程序都是单线程的。

    The GIL, although used by interpreters for other languages like Ruby, is not the only solution to this problem. Some languages avoid the requirement of a GIL for thread-safe memory management by using approaches other than reference counting, such as garbage collection.

    尽管解释器用于其他语言(例如Ruby),但GIL并不是解决此问题的唯一方法。 某些语言通过使用引用计数以外的方法(例如垃圾回收)来避免对线程安全的内存管理使用GIL的要求。

    On the other hand, this means that those languages often have to compensate for the loss of single threaded performance benefits of a GIL by adding other performance boosting features like JIT compilers.

    另一方面,这意味着这些语言通常必须通过添加其他性能提升功能(如JIT编译器)来弥补GIL的单线程性能优势的损失。

    为什么选择GIL作为解决方案? (Why was the GIL chosen as the solution?)

    So, why was an approach that is seemingly so obstructing used in Python? Was it a bad decision by the developers of Python?

    那么,为什么在Python中使用了一种看起来如此阻碍的方法呢? Python开发人员是否会做出错误的决定?

    Well, in the words of Larry Hastings, the design decision of the GIL is one of the things that made Python as popular as it is today.

    好吧,用Larry Hastings话来说, GIL的设计决定是使Python像今天一样流行的原因之一。

    Python has been around since the days when operating systems did not have a concept of threads. Python was designed to be easy-to-use in order to make development quicker and more and more developers started using it.

    自从操作系统没有线程概念以来,Python就已经存在了。 Python被设计为易于使用,以加快开发速度,越来越多的开发人员开始使用它。

    A lot of extensions were being written for the existing C libraries whose features were needed in Python. To prevent inconsistent changes, these C extensions required a thread-safe memory management which the GIL provided.

    现有的C库正在编写许多扩展,这些C需要在Python中实现其功能。 为了防止不一致的更改,这些C扩展需要GIL提供的线程安全内存管理。

    The GIL is simple to implement and was easily added to Python. It provides a performance increase to single-threaded programs as only one lock needs to be managed.

    GIL易于实现,并且很容易添加到Python中。 由于只需要管理一个锁,因此它可以提高单线程程序的性能。

    C libraries that were not thread-safe became easier to integrate. And these C extensions became one of the reasons why Python was readily adopted by different communities.

    非线程安全的C库变得易于集成。 这些C扩展成为Python被不同社区轻易采用的原因之一。

    As you can see, the GIL was a pragmatic solution to a difficult problem that the CPython developers faced early on in Python’s life.

    如您所见,GIL是CPython开发人员在Python生命早期面临的一个难题的务实解决方案。

    对多线程Python程序的影响 (The impact on multi-threaded Python programs)

    When you look at a typical Python program—or any computer program for that matter—there’s a difference between those that are CPU-bound in their performance and those that are I/O-bound.

    当您查看典型的Python程序(或与此相关的任何计算机程序)时,受CPU限制的性能与受I / O限制的性能之间是有区别的。

    CPU-bound programs are those that are pushing the CPU to its limit. This includes programs that do mathematical computations like matrix multiplications, searching, image processing, etc.

    受CPU约束的程序是将CPU推到极限的程序。 这包括进行数学计算的程序,例如矩阵乘法,搜索,图像处理等。

    I/O-bound programs are the ones that spend time waiting for Input/Output which can come from a user, file, database, network, etc. I/O-bound programs sometimes have to wait for a significant amount of time till they get what they need from the source due to the fact that the source may need to do its own processing before the input/output is ready, for example, a user thinking about what to enter into an input prompt or a database query running in its own process.

    受I / O约束的程序是花费时间等待输入/输出的程序,它可能来自用户,文件,数据库,网络等。受I / O约束的程序有时必须等待大量时间,直到它们进入由于源可能需要在输入/输出准备好之前进行自己的处理,因此可以从源那里获得他们需要的东西,例如,用户考虑要在输入提示中输入什么内容或在其输入中运行数据库查询自己的过程。

    Let’s have a look at a simple CPU-bound program that performs a countdown:

    让我们看一个执行倒计时的简单的受CPU约束的程序:

    Running this code on my system with 4 cores gave the following output:

    在具有4个内核的系统上运行此代码,输出如下:

     $ python single_threaded.py
    $ python single_threaded.py
    Time taken in seconds - 6.20024037361145
    Time taken in seconds - 6.20024037361145
    

    Now I modified the code a bit to do to the same countdown using two threads in parallel:

    现在,我使用两个并行线程对代码进行了一些修改,以实现相同的倒计时:

    And when I ran it again:

    当我再次运行它时:

     $ python multi_threaded.py
    $ python multi_threaded.py
    Time taken in seconds - 6.924342632293701
    Time taken in seconds - 6.924342632293701
    

    As you can see, both versions take almost same amount of time to finish. In the multi-threaded version the GIL prevented the CPU-bound threads from executing in parellel.

    如您所见,两个版本花费的时间几乎相同。 在多线程版本中,GIL阻止CPU绑定的线程并行执行。

    The GIL does not have much impact on the performance of I/O-bound multi-threaded programs as the lock is shared between threads while they are waiting for I/O.

    GIL对受I / O绑定的多线程程序的性能影响不大,因为线程在等待I / O时共享锁。

    But a program whose threads are entirely CPU-bound, e.g., a program that processes an image in parts using threads, would not only become single threaded due to the lock but will also see an increase in execution time, as seen in the above example, in comparison to a scenario where it was written to be entirely single-threaded.

    但是,如上例所示,线程完全受CPU约束的程序(例如使用线程处理映像的程序)不仅会由于锁定而变为单线程,而且执行时间也会增加。与将其编写为完全单线程的方案相比。

    This increase is the result of acquire and release overheads added by the lock.

    这种增加是锁增加了获取和释放开销的结果。

    为什么还没有删除GIL? (Why hasn’t the GIL been removed yet?)

    The developers of Python receive a lot of complaints regarding this but a language as popular as Python cannot bring a change as significant as the removal of GIL without causing backward incompatibility issues.

    Python的开发人员对此有很多抱怨,但是像Python这样流行的语言在不引起向后不兼容的问题的情况下,不能带来与删除GIL一样重大的变化。

    The GIL can obviously be removed and this has been done multiple times in the past by the developers and researchers but all those attempts broke the existing C extensions which depend heavily on the solution that the GIL provides.

    GIL显然可以删除,并且开发人员和研究人员过去已经做过多次,但是所有这些尝试都破坏了现有的C扩展,这些扩展在很大程度上取决于GIL提供的解决方案。

    Of course, there are other solutions to the problem that the GIL solves but some of them decrease the performance of single-threaded and multi-threaded I/O-bound programs and some of them are just too difficult. After all, you wouldn’t want your existing Python programs to run slower after a new version comes out, right?

    当然,对于GIL解决的问题,还有其他解决方案,但是其中一些解决方案降低了单线程和多线程I / O绑定程序的性能,其中有些太难了。 毕竟,您不希望新版本发布后现有的Python程序运行速度变慢,对吧?

    The creator and BDFL of Python, Guido van Rossum, gave an answer to the community in September 2007 in his article “It isn’t Easy to remove the GIL”:

    Python的创建者和BDFL的Guido van Rossum在2007年9月的文章“删除GIL并不容易”中向社区做出了回答:

    “I’d welcome a set of patches into Py3k only if the performance for a single-threaded program (and for a multi-threaded but I/O-bound program) does not decrease”

    “只有在单线程程序(以及多线程但受I / O绑定的程序)的性能不降低的情况下,我才欢迎在Py3k中安装一组补丁程序”

    And this condition hasn’t been fulfilled by any of the attempts made since.

    此后的任何尝试都未满足此条件。

    为什么在Python 3中未将其删除? (Why wasn’t it removed in Python 3?)

    Python 3 did have a chance to start a lot of features from scratch and in the process, broke some of the existing C extensions which then required changes to be updated and ported to work with Python 3. This was the reason why the early versions of Python 3 saw slower adoption by the community.

    Python 3确实有机会从头开始启动许多功能,并且在此过程中破坏了一些现有的C扩展,这些扩展随后需要进行更新并移植到Python 3才能使用。这就是早期版本的原因。 Python 3的社区采用速度较慢。

    But why wasn’t GIL removed alongside?

    但是为什么不将GIL一起删除呢?

    Removing the GIL would have made Python 3 slower in comparison to Python 2 in single-threaded performance and you can imagine what that would have resulted in. You can’t argue with the single-threaded performance benefits of the GIL. So the result is that Python 3 still has the GIL.

    与单线程性能相比,删除GIL会使Python 3的速度比Python 2慢,并且您可以想象会导致什么。您无法反对GIL的单线程性能的好处。 因此,结果是Python 3仍然具有GIL。

    But Python 3 did bring a major improvement to the existing GIL—

    但是Python 3确实对现有GIL进行了重大改进-

    We discussed the impact of GIL on “only CPU-bound” and “only I/O-bound” multi-threaded programs but what about the programs where some threads are I/O-bound and some are CPU-bound?

    我们讨论了GIL对“仅与CPU绑定”和“仅与I / O绑定”的多线程程序的影响,但是其中某些线程受I / O绑定而某些线程与CPU绑定的程序又如何呢?

    In such programs, Python’s GIL was known to starve the I/O-bound threads by not giving them a chance to acquire the GIL from CPU-bound threads.

    在这样的程序中,众所周知,Python的GIL会给I / O绑定线程带来饥饿,因为它们没有机会从CPU绑定线程获取GIL。

    This was because of a mechanism built into Python that forced threads to release the GIL after a fixed interval of continuous use and if nobody else acquired the GIL, the same thread could continue its use.

    这是因为Python内置了一种机制,该机制强制线程在固定的连续使用时间间隔后释放GIL,如果没有其他人获得GIL,则同一线程可以继续使用它。

    The problem in this mechanism was that most of the time the CPU-bound thread would reacquire the GIL itself before other threads could acquire it. This was researched by David Beazley and visualizations can be found here.

    这种机制的问题在于,在大多数情况下,CPU绑定线程会在其他线程无法获取GIL之前重新获取GIL本身。 这是David Beazley进行的研究,可以在此处找到可视化效果。

    This problem was fixed in Python 3.2 in 2009 by Antoine Pitrou who added a mechanism of looking at the number of GIL acquisition requests by other threads that got dropped and not allowing the current thread to reacquire GIL before other threads got a chance to run.

    这个问题在2009年的Python 3.2中由Antoine Pitrou修复,他添加了一种机制来查看被其他线程丢弃的GIL获取请求的数量,并且不允许当前线程在其他线程有机会运行之前重新获取GIL。

    如何处理Python的GIL (How to deal with Python’s GIL)

    If the GIL is causing you problems, here a few approaches you can try:

    如果GIL给您造成问题,请尝试以下几种方法:

    Multi-processing vs multi-threading: The most popular way is to use a multi-processing approach where you use multiple processes instead of threads. Each Python process gets its own Python interpreter and memory space so the GIL won’t be a problem. Python has a multiprocessing module which lets us create processes easily like this:

    多处理与多线程:最流行的方法是使用多处理方法,其中您使用多个进程而不是线程。 每个Python进程都有自己的Python解释器和内存空间,因此GIL不会成为问题。 Python有一个multiprocessing模块,使我们可以轻松地创建如下过程:

     from from multiprocessing multiprocessing import import Pool
    Pool
    import import time
    
    time
    
    COUNT COUNT = = 50000000
    50000000
    def def countdowncountdown (( nn ):
        ):
        while while nn >> 00 :
            :
            n n -= -= 1
    
    1
    
    if if __name__ __name__ == == '__main__''__main__' :
        :
        pool pool = = PoolPool (( processesprocesses == 22 )
        )
        start start = = timetime .. timetime ()
        ()
        r1 r1 = = poolpool .. apply_asyncapply_async (( countdowncountdown , , [[ COUNTCOUNT //// 22 ])
        ])
        r2 r2 = = poolpool .. apply_asyncapply_async (( countdowncountdown , , [[ COUNTCOUNT //// 22 ])
        ])
        poolpool .. closeclose ()
        ()
        poolpool .. joinjoin ()
        ()
        end end = = timetime .. timetime ()
        ()
        printprint (( 'Time taken in seconds -''Time taken in seconds -' , , end end - - startstart )
    )
    

    Running this on my system gave this output:

    在我的系统上运行此输出:

    A decent performance increase compared to the multi-threaded version, right?

    与多线程版本相比,性能提高了,对吗?

    The time didn’t drop to half of what we saw above because process management has its own overheads. Multiple processes are heavier than multiple threads, so, keep in mind that this could become a scaling bottleneck.

    时间并没有减少到我们上面看到的一半,因为流程管理有其自己的开销。 多个进程比多个线程重,因此请记住,这可能会成为扩展瓶颈。

    Alternative Python interpreters: Python has multiple interpreter implementations. CPython, Jython, IronPython and PyPy, written in C, Java, C# and Python respectively, are the most popular ones. GIL exists only in the original Python implementation that is CPython. If your program, with its libraries, is available for one of the other implementations then you can try them out as well.

    可选的Python解释器: Python具有多种解释器实现。 最受欢迎的分别是用C,Java,C#和Python编写的CPython,Jython,IronPython和PyPy。 GIL仅存在于原始Python实现中,即CPython。 如果您的程序及其库可用于其他实现之一,则也可以尝试一下。

    Just wait it out: While many Python users take advantage of the single-threaded performance benefits of GIL. The multi-threading programmers don’t have to fret as some of the brightest minds in the Python community are working to remove the GIL from CPython. One such attempt is known as the Gilectomy.

    请稍等:尽管许多Python用户利用GIL的单线程性能优势。 多线程程序员不必烦恼,因为Python社区中一些最聪明的人正在努力从CPython中删除GIL。 一种这样的尝试被称为“ Gilectomy”

    The Python GIL is often regarded as a mysterious and difficult topic. But keep in mind that as a Pythonista you’re usually only affected by it if you are writing C extensions or if you’re using CPU-bound multi-threading in your programs.

    Python GIL通常被认为是一个神秘而困难的话题。 但是请记住,作为Pythonista,通常只有在编写C扩展或在程序中使用CPU绑定多线程时才受到它的影响。

    In that case, this article should give you everything you need to understand what the GIL is and how to deal with it in your own projects. And if you want to understand the low-level inner workings of GIL, I’d recommend you watch the Understanding the Python GIL talk by David Beazley.

    在这种情况下,本文应为您提供了解GIL以及如何在您自己的项目中处理GIL所需的一切。 而且,如果您想了解GIL的底层内部工作原理,建议您观看David Beazley的“ 了解Python GIL”演讲。

    翻译自: https://www.pybloggers.com/2018/03/what-is-the-python-global-interpreter-lock-gil/

    python gil全局锁

    展开全文
  • python全局解释器锁GIL

    2019-08-05 12:50:18
    python全局解释器锁GIL 为什么会有GIL 由于物理上得限制,各CPU厂商在核心频率上的比赛已经被多核所取代。为了更有效的利用多核处理器的性能,就出现了多线程的编程方式,而随之带来的就是线程间数据一致性和状态...

    python全局解释器锁GIL

    为什么会有GIL

    由于物理上得限制,各CPU厂商在核心频率上的比赛已经被多核所取代。为了更有效的利用多核处理器的性能,就出现了多线程的编程方式,而随之带来的就是线程间数据一致性和状态同步的困难。即使在CPU内部的Cache也不例外,为了有效解决多份缓存之间的数据同步时各厂商花费了不少心思,也不可避免的带来了一定的性能损失。

    Python当然也逃不开,为了利用多核,Python开始支持多线程。而解决多线程之间数据完整性和状态同步的最简单方法自然就是加锁。 于是有了GIL这把超级大锁,而当越来越多的代码库开发者接受了这种设定后,他们开始大量依赖这种特性(即默认python内部对象是thread-safe的,无需在实现时考虑额外的内存锁和同步操作)。

    慢慢的这种实现方式被发现是蛋疼且低效的。但当大家试图去拆分和去除GIL的时候,发现大量库代码开发者已经重度依赖GIL而非常难以去除了。有多难?做个类比,像MySQL这样的“小项目”为了把Buffer Pool Mutex这把大锁拆分成各个小锁也花了从5.5到5.6再到5.7多个大版为期近5年的时间,并且仍在继续。MySQL这个背后有公司支持且有固定开发团队的产品走的如此艰难,那又更何况Python这样核心开发和代码贡献者高度社区化的团队呢?

    所以简单的说GIL的存在更多的是历史原因。如果推到重来,多线程的问题依然还是要面对,但是至少会比目前GIL这种方式会更优雅。

    GIL是什么

    首先需要明确的一点是GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念。就好比C++是一套语言(语法)标准,但是可以用不同的编译器来编译成可执行代码。有名的编译器例如GCC,INTEL C++,Visual C++等。Python也一样,同样一段代码可以通过CPython,PyPy,Psyco等不同的Python执行环境来执行。像其中的JPython就没有GIL。然而因为CPython是大部分环境下默认的Python执行环境。所以在很多人的概念里CPython就是Python,也就想当然的把GIL归结为Python语言的缺陷。所以这里要先明确一点:GIL并不是Python的特性,Python完全可以不依赖于GIL

    那么CPython实现中的GIL又是什么呢?GIL全称Global Interpreter Lock为了避免误导,我们还是来看一下官方给出的解释:

    In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.)

    好吧,是不是看上去很糟糕?一个防止多线程并发执行机器码的一个Mutex,乍一看就是个BUG般存在的全局锁嘛!别急,我们下面慢慢的分析。

    为什么会有GIL

    由于物理上得限制,各CPU厂商在核心频率上的比赛已经被多核所取代。为了更有效的利用多核处理器的性能,就出现了多线程的编程方式,而随之带来的就是线程间数据一致性和状态同步的困难。即使在CPU内部的Cache也不例外,为了有效解决多份缓存之间的数据同步时各厂商花费了不少心思,也不可避免的带来了一定的性能损失。

    Python当然也逃不开,为了利用多核,Python开始支持多线程。而解决多线程之间数据完整性和状态同步的最简单方法自然就是加锁。 于是有了GIL这把超级大锁,而当越来越多的代码库开发者接受了这种设定后,他们开始大量依赖这种特性(即默认python内部对象是thread-safe的,无需在实现时考虑额外的内存锁和同步操作)。

    慢慢的这种实现方式被发现是蛋疼且低效的。但当大家试图去拆分和去除GIL的时候,发现大量库代码开发者已经重度依赖GIL而非常难以去除了。有多难?做个类比,像MySQL这样的“小项目”为了把Buffer Pool Mutex这把大锁拆分成各个小锁也花了从5.5到5.6再到5.7多个大版为期近5年的时间,并且仍在继续。MySQL这个背后有公司支持且有固定开发团队的产品走的如此艰难,那又更何况Python这样核心开发和代码贡献者高度社区化的团队呢?

    所以简单的说GIL的存在更多的是历史原因。如果推到重来,多线程的问题依然还是要面对,但是至少会比目前GIL这种方式会更优雅。

    GIL的影响

    从上文的介绍和官方的定义来看,GIL无疑就是一把全局排他锁。毫无疑问全局锁的存在会对多线程的效率有不小影响。甚至就几乎等于Python是个单线程的程序。,全局锁只要释放的勤快效率也不会差啊。只要在进行耗时的IO操作的时候,能释放GIL,这样也还是可以提升运行效率的嘛。或者说再差也不会比单线程的效率差吧。理论上是这样,而实际上呢?Python比你想的更糟。

    展开全文
  • 简而言之,Python全局解释器锁或GIL是一种互斥锁(或锁),仅允许一个线程持有Python解释器的控制权。 这意味着在任何时间点只有一个线程可以处于执行状态。对于执行单线程程序的开发人员而言,GIL的影响并不明显,...
  • Python 的原始解释器 CPython 中存在着 GIL(Global Interpreter Lock,全局解释器锁),因此在解释执行 Python 代码时,会产生互斥锁来限制线程对共享资源的访问,直到解释器遇到 I/O 操作或者操作次数达到一定...
  • 超过十年以上,没有比解释器全局锁(GIL)让Python新手和专家更有挫折感或者更有好奇心。Python的底层要理解GIL的含义,我们需要从Python的基础讲起。像C++这样的语言是编译型语言,所谓编译型语言,是指程序输入到...
  • https://www.jianshu.com/p/de0b71cada92 1,GIL简介 GIL的全称是Global Interpreter Lock(全局解释器锁), 1.1,为何要引入GIL? 首先,看看多核cpu的元年和python的诞生日期: 多核cpu的发展历...
  • 转载出处:原文链接 Python进阶——为什么GIL让多线程变得如此鸡肋? 做 Python 开发时,想必你肯定听过 GIL,它经常被 Python ...查阅官方文档,GIL 全称 Global Interpreter Lock,即全局解释器锁,它的官方解释如下
  • 首先,在python中,多线程是假的多线程,前提你是用的C语言的python解释器,(cpython),在cpython中因为有全局解释器锁GIL的存在,使得python程序在同一时刻只会有一个线程在运行,如果你非要实现在同一时刻真正...
  • 什么是全局解释器锁GIL 首先需要明确的一点是GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念。就好比C++是一套语言(语法)标准,但是可以用不同的编译器来编译成可执行代码。有名的...
  • Python 多线程当中,存在一个叫Global Interpreter Lock(GIL)的东西,直译就是全局解释器锁。它的作用在于让同一时刻只能有一个线程对于python对象进行操作。Python已经提供了各种机制让我们进行多线程同步,为...
  • GIL(Global Interpreter Lock,即全局解释器锁),Python实质上并不存在真正的多线程,只有一个主线程在调度,由于GIL采用轮流运行线程的机制,GIL需要在线程之间不断轮流进行切换,线程如果较
  • 参考资料: Python 的 GIL 是什么鬼,多线程性能究竟如何 深入理解 GIL:如何写出高性能及线程安全的 Python 代码 Python 线程,GIL 和 ctypes
  • 全局解释器锁(GIL Global Interpreter Lock ) GIL锁与python语言并没有什么关系,仅仅是用C语言编写的cpython解释器中存在GIL锁。 在同一个进程中只要有一个线程获取了全局解释器(cpu)的使用权限,那么其他线程...
  • GIL即全局解释器锁,是属于解释器层面的互斥锁,确切的说是CPython解释器内部的一把锁。GIL是为了锁定整个解释器内部的全局资源,每个线程想要运行首先获取GIL,而GIL本身又是一把互斥锁,造成所有线程只能一个一个...
  • 1.什么是全局解释器锁GIL Python代码的执行由Python 虚拟机(也叫解释...对Python 虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。 2.在多线程环境中,Python 虚拟机按...
  • 超过十年以上,没有比解释器全局锁(GIL)让Python新手和专家更有挫折感或者更有好奇心。  Python的底层  要理解GIL的含义,我们需要从Python的基础讲起。像C++这样的语言是编译型语言,所谓编译型语言,是指...
  • global interpreter lock,即python为了保护线程安全而采取的独立线程运行的限制。就是一个内核在一个时间点只能运行一个线程,对于io密集型任务,多线程能起到作用,对于cpu密集型,对线程就无能无力,反而还会因为...
  • GIL的全称是Global Interpreter Lock(全局解释器锁),来源是python设计之初的考虑,为了数据安全所做的决定。 2、每个CPU在同一时间只能执行一个线程(在单核CPU下的多线程其实都只是并发,不是并行,并发和并行从...
  • Python中的GIL(Global Interpreter Lock)全局解释器锁是什么?

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,954
精华内容 781
关键字:

python全局解释器锁

python 订阅