线程安全及Python中的GIL原理分析
本文讲述了线程安全及Python中的GIL。分享给大家供大家参考,具体如下:
摘要
什么是线程安全?为什么python会使用GIL的机制?
在多核时代的到来的背景下,基于多线程来充分利用硬件的编程方法也不断发展起来,但是一旦牵扯到多线程,就必然会涉及到一个概念,即线程安全,本文就主要谈下笔者对线程安全的一些理解.
而Python为很多人所抱怨的一点就是GIL,那么python为什么选择使用GIL,本文也就这个问题进行一些讨论.
引入
你的PC或者笔记本还是单核吗?如果是,那你已经out了.
随着纳米技术的不断进步,计算机芯片的工艺也在进步,但是已经很难在工艺上的改进来提高运算速度而满足摩尔定理,所以intel,amd相继在采用横向的扩展即增加更多的CPU,从而双核,4核,N核不断推出,于是我们进入了多核时代.
于是一个问题出现了,多核时代的出现对于我们程序员而言意味着什么,我们如何利用多核的优势?
在回答这个问题之前,建议对进程和线程不熟悉的读者可以先补下相关的知识.
当然方案是,可以采用多进程,也可以采用多线程.二者的最大区别就是,是否共享资源,后者是共享资源的,而前者是独立的.所以你也可能想起了googlechrome为什么又开始使用独立的进程来作为每个tab服务了(不共享数据,意味着有更好的安全性).
相对于进程的轻型特征,多线程环境有个最大的问题就是如何保证资源竞争,死锁,数据修改等.
于是,便有了线程安全(threadsafety)的提出.
线程安全
Threadsafetyisacomputerprogrammingconceptapplicableinthecontextofmulti-threadedprograms.
Apieceofcodeisthread-safeifitfunctionscorrectlyduringsimultaneousexecutionbymultiplethreads.
Inparticular,itmustsatisfytheneedformultiplethreadstoaccessthesameshareddata,
andtheneedforasharedpieceofdatatobeaccessedbyonlyonethreadatanygiventime.
上面是wikipedia中的解释,换句话说,线程安全是在多线程的环境下,线程安全能够保证多个线程同时执行时程序依旧运行正确,而且要保证对于共享的数据,可以由多个线程存取,但是同一时刻只能有一个线程进行存取.
既然,多线程环境下必须存在资源的竞争,那么如何才能保证同一时刻只有一个线程对共享资源进行存取?
加锁,对,加锁可以保证存取操作的唯一性,从而保证同一时刻只有一个线程对共享数据存取.
通常加锁也有2种不同的粒度的锁:
- fine-grained(所谓的细粒度),那么程序员需要自行地加,解锁来保证线程安全
- coarse-grained(所谓的粗粒度),那么语言层面本身维护着一个全局的锁机制,用来保证线程安全
前一种方式比较典型的是java,Jython等,后一种方式比较典型的是CPython(即Python).
前一种本文不进行讨论,具体可参考java中的多线程编程部分.
至于Python中的全局锁机制,也即GIL(GlobalInterpreterLock),下面主要进行一些讨论.
GIL
什么是GIL?答案可参考wikipedia中的说明,简单地说就是:
每一个interpreter进程,只能同时仅有一个线程来执行,获得相关的锁,存取相关的资源.
那么很容易就会发现,如果一个interpreter进程只能有一个线程来执行,多线程的并发则成为不可能,即使这几个线程之间不存在资源的竞争.
从理论上讲,我们要尽可能地使程序更加并行,能够充分利用多核的功能,那么Python为什么要使用全局的GIL来限制这种并行呢?
这个问题,其实已经得到了很多的讨论,不止十年,可以参考下面的文档:
反对GIL的声音:
- AnopenlettertoGuidovanRossum(这个文章值得一看,下面有很多的留言也值得一看)
认为GIL不能去除的:
- Itisn'tEasytoRemovetheGIL(这个文章来自python作者Guido,他说明了什么要使用GIL)
其它的一些讨论很容易从Google来搜索得到,譬如:GILatgoogle.
那么,简单总结下双方的观点.
认为应该去除GIL的:
- 不顺应计算机的发展潮流(多核时代已经到来,而GIL会很影响多核的使用)
- 大幅度提升多线程程序的速度
认为不应该去除GIL的(如果去掉,会):
- 写python的扩展(module)时会遇到锁的问题,程序员需要繁琐地加解锁来保证线程安全
- 会较大幅度地减低单线程程序的速度
后者是Guido最为关切的,也是不去除GIL最重要的原因,一个简单的尝试是在1999年(十年前),最终的结果是导致单线程的程序速度下降了几乎2倍.
归根结底,其实就是多进程与多线程的选择问题,有一段话比较有意思,可以参考http://www.artima.com/forums/flat.jsp?forum=106&thread=214235.
我引用如下:
Iactuallydon'tthinkremovingtheGILisagoodsolution.
ButIdon'tthinkthreadsareagoodsolution,either.
They'retoohardtogetright,andIsaythatafterspendingliterallyyearsstudyingthreadinginbothC++andJava.
BrianGoetzhastakentosayingthatnoonecangetthreadingright.
引自BruceEckel对Guido的回复.而BruceEckel是何许人,如果你了解java或者C++,那么应该不会不知道他.
个人的观点
那么,从我自己的角度来看(我没有太多的多线程编程经验),先不论多线程的速度优势等,我更加喜欢多进程的是:
- 简单,无需要人为(或者语言级别)的加解锁.想想java中的多线程编程,程序员通常会在此处出错(java程序员可以思考下)
- 安全,这也是浏览器为什么开始使用多进程的一个原因
依照Python自身的哲学,简单是一个很重要的原则,所以,使用GIL也是很好理解的.
当然你真的需要充分利用多核的速度优势,此时python可能并非你最佳的选择,请考虑别的语言吧,如java,erlang等.
更多关于Python相关内容感兴趣的读者可查看本站专题:《Python进程与线程操作技巧总结》、《Python数据结构与算法教程》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python入门与进阶经典教程》、《Python+MySQL数据库程序设计入门教程》及《Python常见数据库操作技巧汇总》
希望本文所述对大家Python程序设计有所帮助。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。