加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

【Python】【并行计算】Python的GIL是什么鬼,多线程性能究竟如

发布时间:2020-12-17 01:23:43 所属栏目:Python 来源:网络整理
导读:原文转自:http://cenalulu.github.io/python/gil-in-python/ div class="inner-wrap" style="color:rgb(49,49,48);font-family:Georgia,Times,'Times New Roman',serif;font-size:16px;" div id="content" class="page-content" style="margin-left:0px;" b

原文转自:http://cenalulu.github.io/python/gil-in-python/

<div class="inner-wrap" style="color:rgb(49,49,48);font-family:Georgia,Times,'Times New Roman',serif;font-size:16px;">
<div id="content" class="page-content" style="margin-left:0px;">
<blockquote style="font-style:italic;border-left:4px solid rgb(221,221,221);">
<p style="line-height:1.5;">前言:博主在刚接触Python的时候时常听到GIL这个词,并且发现这个词经常和Python无法高效的实现多线程划上等号。本着不光要知其然,还要知其所以然的研究态度,博主搜集了各方面的资料,花了一周内几个小时的闲暇时间深入理解了下GIL,并归纳成此文,也希望读者能通过次本文更好且客观的理解GIL。

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

为了避免误导,我们还是来看一下官方给出的解释:


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



<span class="kn" style="color:rgb(133,153,0);">from <span class="nn" style="color:rgb(147,161,161);">threading <span class="kn" style="color:rgb(133,0);">import <span class="n" style="color:rgb(147,161);">Thread
<span class="kn" style="color:rgb(133,0);">import <span class="nn" style="color:rgb(147,161);">time

<span class="k" style="color:rgb(133,0);">def <span class="nf" style="color:rgb(38,139,210);">mycounter<span class="p" style="color:rgb(147,161);">():
<span class="n" style="color:rgb(147,161);">i <span class="o" style="color:rgb(133,0);">= <span class="mi" style="color:rgb(42,152);">0
<span class="k" style="color:rgb(133,0);">for <span class="n" style="color:rgb(147,161);">
<span class="ow" style="color:rgb(133,0);">in <span class="nb" style="color:rgb(181,137,0);">range<span class="p" style="color:rgb(147,161);">(<span class="mi" style="color:rgb(42,152);">100000000<span class="p" style="color:rgb(147,161);">):
<span class="n" style="color:rgb(147,0);">= <span class="n" style="color:rgb(147,0);">+ <span class="mi" style="color:rgb(42,152);">1
<span class="k" style="color:rgb(133,0);">return <span class="bp" style="color:rgb(38,210);">True

<span class="k" style="color:rgb(133,210);">main<span class="p" style="color:rgb(147,161);">thread_array <span class="o" style="color:rgb(133,0);">= <span class="p" style="color:rgb(147,161);">{}
<span class="n" style="color:rgb(147,161);">start_time <span class="o" style="color:rgb(133,161);">time<span class="o" style="color:rgb(133,0);">.<span class="n" style="color:rgb(147,161);">time<span class="p" style="color:rgb(147,161);">()
<span class="k" style="color:rgb(133,161);">tid <span class="ow" style="color:rgb(133,152);">2<span class="p" style="color:rgb(147,161);">t <span class="o" style="color:rgb(133,161);">Thread<span class="p" style="color:rgb(147,161);">(<span class="n" style="color:rgb(147,161);">target<span class="o" style="color:rgb(133,0);">=<span class="n" style="color:rgb(147,161);">my_counter<span class="p" style="color:rgb(147,161);">)
<span class="n" style="color:rgb(147,161);">t<span class="o" style="color:rgb(133,161);">start<span class="p" style="color:rgb(147,161);">()
<span class="n" style="color:rgb(147,161);">join<span class="p" style="color:rgb(147,161);">()
<span class="n" style="color:rgb(147,161);">end_time <span class="o" style="color:rgb(133,0);">print<span class="p" style="color:rgb(147,161);">(<span class="s" style="color:rgb(42,152);">"Total time: {}"<span class="o" style="color:rgb(133,161);">format<span class="p" style="color:rgb(147,0);">- <span class="n" style="color:rgb(147,161);">start_time<span class="p" style="color:rgb(147,161);">))

<span class="k" style="color:rgb(133,0);">if <span class="n" style="color:rgb(147,161);">name <span class="o" style="color:rgb(133,0);">== <span class="s" style="color:rgb(42,152);">'main'<span class="p" style="color:rgb(147,161);">:
<span class="n" style="color:rgb(147,161);">main<span class="p" style="color:rgb(147,161);">()


<h4 id="同时执行的两个并发线程multi_threadpy" style="font-family:'Helvetica Neue',sans-serif;line-height:1;">
同时执行的两个并发线程(multi_thread.py)

 
     

测试结果一


 
     
      
         
     
    

之间几乎是没有间隙的。所以当其他在其他核心上的线程被唤醒时,大部分情况下主线程已经又再一次获取到GIL了。这个时候被唤醒执行的线程只能白白的浪费CPU时间,看着另一个线程拿着GIL欢快的执行着。然后达到切换时间后进入待调度状态,再被唤醒,再等待,以此往复恶性循环。

GIL Performance

由图可见,GIL的存在导致多线程无法很好的立即多核CPU的并发处理能力。

GIL IO Performance


(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读