【问题标题】:Python, counter atomic incrementPython,计数器原子增量
【发布时间】:2014-05-08 16:37:44
【问题描述】:

如何将以下代码从 Java 转换为 Python?

AtomicInteger cont = new AtomicInteger(0);

int value = cont.getAndIncrement();

【问题讨论】:

  • 你真的在你的 Python 应用程序中使用线程吗?
  • 是的。我有一个包含 100 个线程的池,我需要在每个线程中增加一个变量。

标签: python


【解决方案1】:

最有可能在该值的任何用法周围使用threading.Lock。除非您使用 pypy,否则 Python 中没有原子修改(如果您这样做,请查看 stm 版本中的__pypy__.thread.atomic)。

【讨论】:

  • 我使用acquire() 和release() 的锁它可以工作,但我认为它不像Java 中的原子类那样高效。
  • with your_lock: variable += 1 可能更短。
  • @viraptor,不要忘记在锁仍然持有时从variable 中取出value
  • 仅供参考:暂停和恢复线程的成本很高,因此在 java 中实现原子,它执行重复的比较和交换操作而不是锁定:baeldung.com/java-atomic-variables
【解决方案2】:

itertools.count 返回一个迭代器,它将在每次迭代中执行与getAndIncrement() 等效的操作。

例子:

import itertools
cont = itertools.count()
value = next(cont)

【讨论】:

  • 乍一看这似乎不是线程安全的,是吗?
  • 暂时忽略我对使用依赖 GIL 进行同步的定时炸弹的犹豫,是什么让你说这绝对是一个单一的操作?这是一个单一的函数调用,但它是一个单一的字节码操作吗?
  • Yes
  • @JianggeZhang 我还是同意 Colin 的犹豫。在许多情况下,依靠应急进行同步是不明智的:即,它当前如何实现的隐含细节超出了“合同”和方法的意图.无异于依赖副作用。在某些情况下,这可能没问题,但 imo 总的来说还是有问题
  • @WillManley 它依赖于 CPython(和 PyPy)的实现细节,依赖实现细节不是一个好习惯。此外,在 Jython 上也不安全,请参阅:jython.org/jythonbook/en/1.0/… 和:bitbucket.org/jython/jython/src/… 请更新帖子。
【解决方案3】:

这将执行相同的功能,尽管它不像名称“AtomicInteger”所暗示的那样是无锁的。

注意其他方法也不是严格无锁的——它们依赖于 GIL 并且不能在 python 解释器之间移植。

class AtomicInteger():
    def __init__(self, value=0):
        self._value = int(value)
        self._lock = threading.Lock()
        
    def inc(self, d=1):
        with self._lock:
            self._value += int(d)
            return self._value

    def dec(self, d=1):
        return self.inc(-d)    

    @property
    def value(self):
        with self._lock:
            return self._value

    @value.setter
    def value(self, v):
        with self._lock:
            self._value = int(v)
            return self._value

【讨论】:

  • 为什么要锁定 value()... 不是自己检索原子操作吗??
  • 听起来不错。虽然,您还需要检查 value 始终是 int ,而不是提升为长的、虚构的或某种非原子对象。 (例如,如果您将 MyLoggingInt 提供给构造函数会发生什么)
  • 所有这些不只是阅读参考吗?您要么得到旧值,要么得到新值。 (如果不是,python真的是一团糟)……是吗?
  • 实际上,我不确定您是否可以假设。是self.x。原子。它当然不是总是原子的(因为__getattr__、__getattribute__ 可能在子类中实现。(另外,我添加了 int(x) 以保护输入不是不可变的线程安全的情况)对象)。
  • 不幸的是,这在我的情况下非常昂贵,并且没有按预期工作(即不是 100% 原子)。
【解决方案4】:

使用 atomics 库,在 Python 中也可以这样写:

import atomics


a = atomics.atomic(width=4, atype=atomics.INT)

value = a.fetch_inc()

这种方法是严格无锁的。

注意:我是这个库的作者

【讨论】:

  • 您好像在推荐自己的库。请注意,如果是自我推销,"you must disclose your affiliation in your answers".
  • 抱歉,我现在就这么做(包括其他 cmets)
  • 别担心,只是想让您知道。顺便说一句,干得好。
  • 嗨。我只是这里的路人,幸运的是刚刚找到了你的答案。很高兴它是在几个小时前发布的。那么,让我问你:width=4 是什么?阅读文档对我来说并不清楚。另外,我为什么要关心宽度呢?此外,文档应该包含一个 GitHub 链接以供贡献,并提供新手可以理解的简单案例,例如此答案中的案例,而不是直接跳到复杂的内容,例如在具有大量并发或内存映射访问的多个线程中测试其正确性。
  • 无论如何,恭喜你提供了这样的库。
猜你喜欢
  • 2010-12-08
  • 1970-01-01
  • 2021-03-09
  • 1970-01-01
  • 1970-01-01
  • 2015-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多