线程安全是在多线程的环境下,能够保证多个线程同时执行时程序依旧运行正确, 而且要保证对于共享的数据可以由多个线程存取,但是同一时刻只能有一个线程进行存取。多线程环境下解决资源竞争问题的办法是加锁来保证存取操作的唯一性。
通常加锁也有2种不同的粒度的锁:
1. fine-grained(细粒度),程序员需要自行加/解锁来保证线程安全
2. coarse-grained(粗粒度),语言层面本身维护着一个全局的锁机制用来保证线程安全
前一种方式比较典型的是 Java, Jython 等, 后一种方式比较典型的是 CPython (即Python)。
前一种方式具体可参考 java 中的多线程编程部分,至于Python中的全局锁机制,也即 GIL (Global Interpreter Lock)。简单地说就是每一个interpreter进程,只能同时仅有一个线程来执行,获得相关的锁,存取相关的资源。那么问题来了,如果一个interpreter进程只能有一个线程,多线程的并发则成为不可能,即使这几个线程之间不存在资源的竞争。
从理论上讲,要尽可能地使程序更加并行,能够充分利用多核的功能,那么Python为什么要使用 GIL 来限制这种并行呢? 这个问题,长久以来已经得到了很多的讨论,更多关于GIL的性能探讨可以参考Python的GIL是什么鬼,多线程性能究竟如何
当然,这也就是说Python中基本数据类型list, dict, tuple等都是线程安全的,而Jython中的多线程操作则需要手动安置同步锁。
总体来看,解决Python中GIL遗留的历史问题不是一个简单工程,如果需要避开这个问题可以使用多进程的编程方式(multi process),但是这又会有进程间通信问题。依照Python自身的哲学, 简单是一个很重要的原则,所以,使用 GIL 也是很好理解的。如果真的需要充分利用多核的速度优势,此时python可能并非最佳选择,可以考虑别的语言,如 java等。