Python原子访问(与线程相关)

时间:2016-10-27 10:43:38

标签: python multithreading thread-safety

当你开始使用线程时,你必须非常了解一些事情,主要是关于共享数据的同步。你必须使用锁,rlocks,信号量等。它是用非常简单的共享数据写的吗?

例如,我有两个共享全局资源的线程,一个简单的布尔变量。

import threading
import random
import time

active = True

class T1(threading.Thread):
    def run(self):
        while active:
            print("Hello")      # do some work
            time.sleep(0.1)

class T2(threading.Thread):
    def run(self):
        global active
        while random.random() > 0.05:
            time.sleep(1)
        active = False

t1, t2 = T1(), T2()
t1.start()
t2.start()
t1.join()
t2.join()

它似乎有效,但python是否保证它有效?如果是的话,究竟是出于什么原因呢?

我有三个答案。

  1. 它的工作原理是因为布尔变量的访问总是原子的(它不能被另一个线程中断)。在这种情况下,Python保证什么是原子操作?是访问整数,列表,字典原子?
  2. Python不保证此代码每次都有效。解决方案是使用锁来访问两个线程中的活动变量。
  3. 它起作用,因为只有一个线程写入变量。另一个线程只读它。
  4. 这是另一个代码:

    import threading
    import random
    import time
    
    numbers = [3]
    
    class T1(threading.Thread):
        def run(self):
            while sum(numbers) % 3 == 0:
                print("Hello")      # do some work
                time.sleep(0.1)
    
    class T2(threading.Thread):
        def run(self):
            global active
            while random.random() > 0.2:
                numbers.extend([1, 2])
                time.sleep(1)
            numbers.append(4)
    
    t1, t2 = T1(), T2()
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    

    现在单一和“复杂”指令 numbers.extend([1,2])可以被T1线程中断吗?如果是这种情况,只需添加1但在添加2之前,T1可能会在T2之前无意中停止。

1 个答案:

答案 0 :(得分:0)

简答:它始终有效(至少在CPython中)

因为GIL(全球翻译锁)而起作用。 https://wiki.python.org/moin/GlobalInterpreterLock

这保证没有两个线程同时执行Python代码,因此永远不会同时读/写。

如果您对某个特定的非CPython实现有疑问,那可能会产生自己的问题。

我认为其他Python实现(除了CPython)确实试图保留使用CPython的程序员所依赖的一些行为,但我不确定每个项目如何/在多大程度上这样做。