在这里我们将介绍Python的GIL和线程安全,希望大家能从中理解Python里的GIL,以及GIL的前世今生。
对于Python的GIL和线程安全很多人不是很了解,通过本文,希望能让大家对Python的GIL等内容有所帮助。本文还将就主要谈下笔者对线程安全的一些理解。
摘要
什么是线程安全? 为什么Python会使用GIL的机制?
在多核时代的到来的背景下,基于多线程来充分利用硬件的编程方法也不断发展起来, 但是一旦 牵扯到多线程,就必然会涉及到一个概念,即 线程安全, 本文就主要谈下笔者对线程安全的一些理解.
而Python为很多人所抱怨的一点就是GIL,那么Python为什么选择使用GIL, 本文也就这个问题进行一些讨论.
Contents
摘要 引入 线程安全 GIL 个人的观点 参考资料 本文的rst源码 . 引入
你的PC或者笔记本还是单核吗? 如果是,那你已经out了.
随着纳米技术的不断进步, 计算机芯片的工艺也在进步,但是已经很难在工艺上的改进来提高 运算速度而满足 摩尔定理, 所以intel, amd相继在采用横向的扩展即增加更多的CPU, 从而双核, 4核, N核不断推出,于是我们进入了多核时代.
于是一个问题出现了, 多核时代的出现对于我们程序员而言意味着什么, 我们如何利用多核的优势?
在回答这个问题之前,建议对 进程 和 线程 不熟悉的读者可以先补下相关的知识.
当然方案是,可以采用 多进程, 也可以采用 多线程. 二者的最大区别就是, 是否共享资源, 后者是共享资源的,而前者是独立的. 所以你也可能想起了google chrome为什么又开始使用独立的进程 来作为每个tab服务了(不共享数据,意味着有更好的安全性).
相对于进程的轻型特征,多线程环境有个最大的问题就是 如何保证资源竞争,死锁, 数据修改等.
于是,便有了 线程安全 (thread safety)的提出.
线程安全
Thread safety is a computer programming concept applicable in the context of multi-threaded programs.A piece of code is thread-safe if it functions correctly during simultaneous execution by multiple threads.In particular, it must satisfy the need for multiple threads to access the same shared data,and the need for a shared piece of data to be accessed by only one thread at any given time.
上面是wikipedia中的解释, 换句话说, 线程安全 是在多线程的环境下, 线程安全能够保证多个线程同时执行时程序依旧运行正确, 而且要保证对于共享的数据,可以由多个线程存取,但是同一时刻只能有一个线程进行存取.
既然,多线程环境下必须存在资源的竞争,那么如何才能保证同一时刻只有一个线程对共享资源进行存取?
加锁, 对, 加锁可以保证存取操作的唯一性, 从而保证同一时刻只有一个线程对共享数据存取.
通常加锁也有2种不同的粒度的锁:
fine-grained(所谓的细粒度), 那么程序员需要自行地加,解锁来保证线程安全
coarse-grained(所谓的粗粒度), 那么语言层面本身维护着一个全局的锁机制,用来保证线程安全
前一种方式比较典型的是 java, Jython 等, 后一种方式比较典型的是 CPython (即Python).
前一种本文不进行讨论, 具体可参考 java 中的多线程编程部分.
至于Python中的全局锁机制,也即 GIL (Global Interpreter Lock), 下面主要进行一些讨论.
Python的GIL
什么是GIL ? 答案可参考wikipedia中的说明, 简单地说就是:
每一个interpreter进程,只能同时仅有一个线程来执行, 获得相关的锁, 存取相关的资源.
那么很容易就会发现,如果一个interpreter进程只能有一个线程来执行, 多线程的并发则成为不可能, 即使这几个线程之间不存在资源的竞争.
从理论上讲,我们要尽可能地使程序更加并行, 能够充分利用多核的功能, 那么Python为什么要使用 全局的GIL 来限制这种并行呢?
这个问题,其实已经得到了很多的讨论, 不止十年, 可以参考下面的文档:
反对GIL的声音:
An open letter to Guido van Rossum (这个文章值得一看,下面有很多的留言也值得一看)
认为GIL不能去除的:
It isn‘t Easy to Remove the GIL (这个文章来自python作者 Guido, 他说明了什么要使用 GIL)
其它的一些讨论很容易从Google来搜索得到, 譬如: GIL at google.
那么,简单总结下双方的观点.
认为应该去除GIL的:
不顺应计算机的发展潮流(多核时代已经到来, 而 GIL 会很影响多核的使用)
大幅度提升多线程程序的速度
认为不应该去除GIL 的(如果去掉,会):
写python的扩展(module)时会遇到锁的问题,程序员需要繁琐地加解锁来保证线程安全
会较大幅度地减低单线程程序的速度
后者是Guido最为关切的, 也是不去除GIL最重要的原因, 一个简单的尝试是在1999年(十年前), 最终的结果是导致单线程的程序速度下降了几乎2倍.
归根结底,其实就是多进程与多线程的选择问题, 有一段话比较有意思, 可以参考 http://www.artima.com/forums/flat.jsp?forum=106&thread=214235.
我引用如下:
I actually don‘t think removing the GIL is a good solution.
But I don‘t think threads are a good solution, either.
They‘re too hard to get right, and I say that after spending literally years studying threading in both C++ and Java.
Brian Goetz has taken to saying that no one can get threading right.
引自Bruce Eckel 对Guido 的回复. 而Bruce Eckel 是何许人, 如果你了解Java 或者C++, 那么应该不会不知道他.
个人的观点
那么,从我自己的角度来看(我没有太多的多线程编程经验), 先不论多线程的速度优势等,我更加喜欢多进程的是:
简单,无需要人为(或者语言级别)的加解锁. 想想 java 中的多线程编程,程序员通常会在此处出错(Java程序员可以思考下)
安全, 这也是浏览器为什么开始使用多进程的一个原因
依照Python自身的哲学, 简单 是一个很重要的原则,所以, 使用 GIL 也是很好理解的.
当然你真的需要充分利用多核的速度优势,此时python可能并非你最佳的选择,请考虑别的语言吧,如Java, erlang 等.
原文标题:线程安全及Python中的GIL
链接:http://www.cnblogs.com/mindsbook/archive/2009/10/15/thread-safety-and-GIL.html