Python实例变量是线程安全的吗?
好的,首先检查以下代码:
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()
来锁定这个资源,有更好的主意吗?
OK, check following codes first:
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()
I'm facing same situation as above. I really want to know if it's thread-safe for self.Counter
, well if not, what options do I have? I can only think of threading.RLock()
to lock this resource, any better idea?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
多个线程同时访问的变量将导致竞争条件和不需要的行为。您必须依赖锁、RLocks、信号量、条件、事件或队列。
以下文章 有助于理解每个事件之间的区别以及何时在多线程环境:
Variables accessed by multiple threads at the same time will lead to race conditions and unwanted behaviours. You must rely on Locks, RLocks, Semaphores, Conditions, Events or Queues.
The following article helps to understand the difference between each and when to use them in a multi-threaded environment:
使用实例字段
self.Counter
是 线程安全或“原子” (或者在这里)。读取它或分配一个单个值 - 即使它需要内存中的 4 个字节,您也永远不会得到一半变化的值。但是操作self.Counter = self.Counter + 1
并不是因为它读取值然后写入它 - 另一个线程可以在读取该字段之后和写入之前更改该字段的值后退。所以你需要用锁来保护整个操作。
由于方法体基本上是整个操作,因此您可以使用装饰器来执行此操作。请参阅此答案的示例:https://stackoverflow.com/a/490090/34088
Using the instance field
self.Counter
is thread safe or "atomic" (or here). Reading it or assigning a single value - even when it needs 4 bytes in memory, you will never get a half-changed value. But the operationself.Counter = self.Counter + 1
is not because it reads the value and then writes it - another thread could change the value of the field after it has been read and before it is written back.So you need to protect the whole operation with a lock.
Since method body is basically the whole operation, you can use a decorator to do this. See this answer for an example: https://stackoverflow.com/a/490090/34088
不,它不是线程安全的 - 两个线程本质上是同时修改同一个变量。是的,解决方案是线程模块中的锁定机制之一。
顺便说一句,
self.Counter
是一个实例变量,而不是类变量。No, it is not thread safe - the two threads are essentially modifying the same variable simultaneously. And yes, the solution is one of the locking mechanisms in the
threading
module.BTW,
self.Counter
is an instance variable, not a class variable.self.Counter 是一个实例变量,因此每个线程都有一个副本。
如果您在
__init__()
之外声明该变量,它将是一个类变量。该类的所有实例将共享该实例。
self.Counter
is an instance variable, so each thread has a copy.If you declare the variable outside of
__init__()
, it will be a class variable.All instances of the class will share that instance.
Atomos 库为 Python 基元和对象提供原子(线程安全)包装器,包括原子计数器。它使用单写入器/多读取器锁。
The Atomos library provides atomic (thread-safe) wrappers for Python primitives and objects, including atomic counters. It uses single-writer/multiple-reader locks.