您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

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

5b51 2022/1/14 8:25:23 python 字数 65745 阅读 858 来源 www.jb51.cc/python

原文转自:http://cenalulu.github.io/python/gil-in-python/ <divclass=\"inner-wrap\"style=\"color:rgb(49,49,48);font-family:Georgia,Times,\'TimesNewRoman\',serif;font-size:16px;\"

概述

原文转自: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的,无需在实现时考虑额外的内存锁和同步操作)。

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


方法很简单,一个循环1亿次的计数器函数一个通过单线程执行两次,一个多线程执行。最后比较执行总时间。测试环境为双核的Mac pro。注:为了减少线程库本身性能损耗对测试结果带来的影响,这里单线程的代码同样使用了线程。只是顺序的执行两次,模拟单线程。


<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这把超级大锁,而当越来越多的代码库开发者接受了这种设定后,他们开始大量依赖这种特性(即认python内部对象是thread-safe的,无需在实现时考虑额外的内存锁和同步操作)。

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


方法很简单,一个循环1亿次的计数器函数一个通过单线程执行两次,一个多线程执行。最后比较执行总时间。测试环境为双核的Mac pro。注:为了减少线程库本身性能损耗对测试结果带来的影响,这里单线程的代码同样使用了线程。只是顺序的执行两次,模拟单线程。


<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);">()

 
     

并不是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的,无需在实现时考虑额外的内存锁和同步操作)。

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

方法很简单,一个循环1亿次的计数器函数一个通过单线程执行两次,一个多线程执行。最后比较执行总时间。测试环境为双核的Mac pro。注:为了减少线程库本身性能损耗对测试结果带来的影响,这里单线程的代码同样使用了线程。只是顺序的执行两次,模拟单线程。

<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);">()

测试结果一

并不是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的,无需在实现时考虑额外的内存锁和同步操作)。

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


,为了有效解决多份缓存之间的数据同步时各厂商花费了不少心思,也不可避免的带来了一定的性能损失。

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

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

,为了有效解决多份缓存之间的数据同步时各厂商花费了不少心思,也不可避免的带来了一定的性能损失。

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

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

方法很简单,一个循环1亿次的计数器函数一个通过单线程执行两次,一个多线程执行。最后比较执行总时间。测试环境为双核的Mac pro。注:为了减少线程库本身性能损耗对测试结果带来的影响,这里单线程的代码同样使用了线程。只是顺序的执行两次,模拟单线程。

方法很简单,一个循环1亿次的计数器函数一个通过单线程执行两次,一个多线程执行。最后比较执行总时间。测试环境为双核的Mac pro。注:为了减少线程库本身性能损耗对测试结果带来的影响,这里单线程的代码同样使用了线程。只是顺序的执行两次,模拟单线程。

方法很简单,一个循环1亿次的计数器函数一个通过单线程执行两次,一个多线程执行。最后比较执行总时间。测试环境为双核的Mac pro。注:为了减少线程库本身性能损耗对测试结果带来的影响,这里单线程的代码同样使用了线程。只是顺序的执行两次,模拟单线程。


<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);">()

<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);">()

<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);">()

 
     

测试结果一

一个pthread,并通过操作系统调度算法进行调度(例如linux是CFS)。为了让各个线程能够平均利用cpu时间,python会计算当前已执行的微代码数量,达到一定阈值后就强制释放GIL。而这时也会触发一次操作系统的线程调度(当然是否真正进行上下文切换由操作系统自主决定)。

代码

 
     
      
         
     
    rating System a chance to do thread scheduling */

一个cpu核心的情况下毫无问题。任何一个线程被唤起时都能成功获得到GIL(因为只有释放了GIL才会引发线程调度)。但当cpu有多个核心的时候,问题就来了。从伪代码可以看到,从Highlighter-rouge" style="font-family:'Bitstream Vera Sans Mono',242);">release GILHighlighter-rouge" style="font-family:'Bitstream Vera Sans Mono',242);">acquire GIL之间几乎是没有间隙的。所以当其他在其他核心上的线程被唤醒时,大部分情况下主线程已经又再一次获取到GIL了。这个时候被唤醒执行的线程只能白白的浪费cpu时间,看着另一个线程拿着GIL欢快的执行着。然后达到切换时间后进入待调度状态,再被唤醒,再等待,以此往复恶性循环。

间的互动关系。例如先尝试持有GIL在做线程上下文切换,在IO等待时释放GIL等尝试。但是无法改变的是GIL的存在使得操作系统线程调度的这个本来就昂贵的操作变得更奢侈了。 

GIL Performance

GIL IO Performance

cpython的产物,那么其他解析器是不是更好呢?没错,像JPython和IronPython这样的解析器由于实现语言的特性,他们不需要GIL的帮助。然而由于用了Java/C#用于解析器实现,他们也失去了利用社区众多C语言模块有用特性的机会。所以这些解析器也因此一直都比较小众。毕竟功能性能大家在初期都会选择前者,Highlighter-rouge" style="font-family:'Bitstream Vera Sans Mono',242);">Done is better than perfect

去除GIL。并在各个小版本中有了不少的进步。有兴趣的读者可以扩展阅读 另一个改进

功能和性能之间权衡后的产物,它尤其存在的合理性,也有较难改变的客观因素。从本分的分析中,我们可以做以下一些简单的总结:

  • 性能
  • 性能较高的程序可以考虑把核心部分也成C模块,或者索性用其他语言实现

功能和性能之间权衡后的产物,它尤其存在的合理性,也有较难改变的客观因素。从本分的分析中,我们可以做以下一些简单的总结:

功能和性能之间权衡后的产物,它尤其存在的合理性,也有较难改变的客观因素。从本分的分析中,我们可以做以下一些简单的总结:

  nofollow" style="color:rgb(34,162);">Revisiting thread priorities and the new GIL

总结

以上是编程之家为你收集整理的【Python】【并行计算】Python的GIL是什么鬼,多线程性能究竟如何全部内容,希望文章能够帮你解决【Python】【并行计算】Python的GIL是什么鬼,多线程性能究竟如何所遇到的程序开发问题。


如果您也喜欢它,动动您的小指点个赞吧

除非注明,文章均由 laddyq.com 整理发布,欢迎转载。

转载请注明:
链接:http://laddyq.com
来源:laddyq.com
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


联系我
置顶