Python实例变量是否是线程安全的?

时间:2011-11-29 11:23:16

标签: python multithreading thread-safety

好的,请先检查以下代码:

class DemoClass():

    def __init__(self):
        #### I really want to know if self.Counter is thread-safe. 
        self.Counter = 0

    def Increase(self):
        self.Counter = self.Counter + 1

    def Decrease(self):
        self.Counter = self.Counter - 1

    def DoThis(self):
        while True:
            Do something

            if A happens:
                self.Increase()
            else:
                self.Decrease()

            time.sleep(randomSecs)

    def DoThat(self):
        while True:
            Do other things

            if B happens:
                self.Increase()
            else:
                self.Decrease()

            time.sleep(randomSecs)

    def ThreadSafeOrNot(self):
        InterestingThreadA = threading.Thread(target = self.DoThis, args = ())
        InterestingThreadA.start()

        InterestingThreadB = threading.Thread(target = self.DoThat, args = ())
        InterestingThreadB.start()

我面临与上述相同的情况。我真的想知道self.Counter是否是线程安全的,如果没有,我有什么选择?我只能想到threading.RLock()来锁定这个资源,还有更​​好的主意吗?

5 个答案:

答案 0 :(得分:31)

您可以使用锁定,RLocks,信号量,条件,事件和队列 这篇文章帮助我很多 看看:Laurent Luce's Blog

答案 1 :(得分:22)

使用实例字段self.Counterthread safe or "atomic"。读取它或分配单个值 - 即使它在内存中需要4个字节,你也永远不会得到一个半变化的值。但是操作self.Counter = self.Counter + 1不是因为它读取值然后写入它 - 另一个线程可以在读取之后和写回之前更改字段的值。

所以你需要用锁来保护整个操作。

由于方法体基本上是整个操作,因此可以使用装饰器来完成此操作。请参阅此答案以获取示例:https://stackoverflow.com/a/490090/34088

答案 2 :(得分:9)

不,它不是线程安全的 - 两个线程实际上是同时修改同一个变量。是的,该解决方案是threading模块中的锁定机制之一。

BTW,self.Counter实例变量,而不是类变量

答案 3 :(得分:1)

self.Counter是一个实例变量,因此每个线程都有一个副本。

如果在__init__()之外声明变量,它将是一个类变量。 该类的所有实例都将共享该实例。

答案 4 :(得分:0)

Atomos 库为 Python 原语和对象(包括原子计数器)提供原子(线程安全)包装器。它使用单写入器/多读取器锁。