为什么我要担心CPython中的线程安全?

时间:2016-08-29 12:21:43

标签: python multithreading thread-safety cpython gil

据我所知,Global Interpreter Lock只允许一个线程访问解释器并执行字节码。如果是这种情况,那么在任何给定时间,只有一个线程将使用解释器及其内存。

有了这个我相信排除有种族案例的可能性是公平的,因为没有两个线程可以同时访问解释器的内存,但我仍然看到关于确保数据结构是“线程安全”的警告。它有可能覆盖python解释器的所有实现(如cython),它可以关闭GIL并允许真正的多线程。

我理解线程安全在没有启用GIL的解释器环境中的重要性。但是,对于CPython,为什么在编写多线程python代码时会鼓励线程安全?在CPython环境中可能发生的更糟糕的是什么?

2 个答案:

答案 0 :(得分:7)

当然竞争条件仍然可以发生,因为对数据结构的访问不是原子的

假设您测试字典中存在的密钥,然后执行添加密钥的操作:

if key not in dictionary:
    # calculate new value
    value = elaborate_calculation()
    dictionary[key] = value

not in测试返回true后,可以在任何时候切换线程,另一个线程也会得出密钥不存在的结论。现在有两个线程在进行计算,你不知道哪一个会赢。

GIL所做的就是保护Python的内部解释器状态。这并不意味着Python代码本身使用的数据结构现在已被锁定和保护。

答案 1 :(得分:0)

一个重要的注意事项:尽管有GIL,但Python中的多处理模块在某种程度上是同步的,因为对同一变量的访问可以同时在不同的进程中进行。

这可能会破坏您的数据,或者至少会破坏您的控制流,这就是建议线程安全的原因。

至于它为什么会发生,尽管只有一个interpriter,但是没有任何东西停止(至少据我所知)两个预先编译的代码同步访问共享内存的相同部分。当说:

import multiprocessing
def my_func ():
    print("hello world")
my_process=multiprocessing.Process (target=my_func, args=(,))
my_process.start ()
my_process.join ()

我的理解是,interprit(在这种情况下)my_func所花费的时间被埋没在产生新进程所需的开销中。

在这种情况下,术语"过程"在这里更合适,因为有一些工作线程只是为了复制数据而暂时产生的,所以有一些数据握手正在进行,所以它实际上是一个不同的过程(双关语)。产生传统线索。

我希望这会有所帮助。