【问题标题】:Are static fields used to modify super class behaviour thread safe?用于修改超类行为的静态字段是否线程安全?
【发布时间】:2014-03-16 19:32:07
【问题描述】:

如果一个子类想通过静态字段修改继承方法的行为,它是线程安全的吗?

更具体地说:

class A (object):
  _m = 0
  def do(self):
     print self._m

class B (A):
  _m=1
  def test(self):
    self.do()

class C (A):
  _m=2
  def test(self):
    self.do()

在多线程环境中,调用 do() 的类 B 的实例是否会表现得像类 C 应该的那样,反之亦然?我会说是的,但我想知道是否有人已经实际测试过这种模式。

注意:这不是关于模式本身的问题,我认为应该避免这个问题,而是关于它的后果,正如我在审查现实生活中的代码时发现的那样。

【问题讨论】:

  • 这可能是实际问题的一个糟糕示例 - 每个类都有一个 不同 _m 变量。
  • 这就是重点:这就是为什么它们可能被不同的并发线程混淆

标签: python multithreading thread-safety subclass


【解决方案1】:

首先,请记住类是对象,而静态字段(以及就此而言,方法)是所述类对象的属性。

所以发生的情况是self.do()self 中查找do 方法并调用do(self)self 设置为正在调用的任何对象,该对象本身引用类ABC 作为其类之一。所以查找会在正确的类中找到_m 的值。

当然,这需要更正您的代码:

class A (object):
  _m = 0
  def do(self):
     if self._m==0: ...
     elif ...

您的原始代码将不起作用,因为 Python 仅在两个位置查找 _m:在函数中定义,或作为全局。它不会像 C++ 那样在类范围内查找。所以你必须以self. 为前缀,这样才能使用正确的前缀。如果你想强制它在class A 中使用_m,你可以改用A._m

附:有时您需要这种模式,尤其是元类,它有点类似于 Python 的 C++ 模板元编程和函数算法。

【讨论】:

  • 我忘了加上前缀 self: 现在添加。请注意,它仅用于说明模式。在单继承的情况下,你不需要在超类前面加上前缀。
  • 问题是关于多线程,而不是代码的有效性。
  • 您的问题是,在多线程代码中,B 类的对象是否会像 C 类的对象一样随机工作。这本质上是模糊的。我只是表明它与对象成员访问一样是线程安全的。也就是说,BC 没有任何理由会表现得像彼此,因为他们甚至看不到彼此的成员。
  • 这并不模糊。 B 和 C 都覆盖了 A 的静态字段:_m。运行 B().do() 给出 1,C().do() 给出 2。如果这 2 个语句同时在 2 个不同的线程中运行怎么办?您在 MT 环境中对此有实际经验吗?
  • 如果你在 CPython 上运行,Python 多线程并不是真正的抢占式;有一个全局解释器锁 (GIL),它最终充当了所有事物的大屏障同步器。至于我的经验,是的,我让 Django 在使用 Apache 服务器的多线程 WSGI 环境中运行,并且它的模型库大量使用元类。然而,我仍然看不出你认为 Python 的内部会发生什么神奇的事情,它会跨越两个不同子类中的两个成员的两个值,以及线程如何触发它。
猜你喜欢
  • 2017-10-05
  • 2011-07-07
  • 1970-01-01
  • 1970-01-01
  • 2019-05-21
  • 1970-01-01
  • 2011-11-29
  • 1970-01-01
  • 2012-09-22
相关资源
最近更新 更多