gpt4 book ai didi

python - 线程安全的 Python 属性/特性?

转载 作者:太空宇宙 更新时间:2023-11-03 12:42:08 26 4
gpt4 key购买 nike

我有如下代码:

class SomeSharedData(object):
def __init__(self):
self._lock = RLock()
self._errors = 0

@property
def errors(self):
with self._lock:
return self._errors

@errors.setter
def errors(self, value):
with self._lock:
self._errors = value

除了具有更多属性,例如 errors。我的目标是易用性,而不是效率,所以过多的锁定是可以的。

是否有更简洁的方式来定义这些属性?

到目前为止我想到的最好的是:

class thread_safe_property(object):
def __init__(self, name=None):
self.name = name

def __get__(self, obj, objtype):
with obj._lock:
return getattr(obj, self.name)

def __set__(self, obj, val):
with obj._lock:
setattr(obj, self.name, val)

class SomeSharedData(object):
def __init__(self):
self._lock = RLock()
self._errors = 0

errors = thread_safe_property('_errors')

想法?更好的方法?

原始代码和新方法都可能遇到像 data.errors += 1 这样的语句的竞争条件,但我很少需要执行这些操作,所以我在需要的地方添加了变通办法。

谢谢!

最佳答案

您可能需要更深入地思考线程安全到底意味着什么。考虑一下您是否改写了这段代码:

class SomeSharedData(object):
def __init__(self):
self.errors = 0

此代码与您发布的代码完全一样是线程安全的。为属性赋值在 Python 中是线程安全的:值总是被赋值;它可能会也可能不会被另一个线程分配的另一个值覆盖,但你总是得到一个值或另一个值,永远不会是两者的混合。同样,访问该属性会为您提供当前值。

您的代码中断的地方是您在原始版本或简化版本中所说的,例如一行:

shared.errors += 1

不是线程安全的,但这就是使您的代码安全的全部意义所在,这些是您需要注意的事情,而不是简单的 get/set。

回答评论中的问题:

Python 中的简单赋值只是简单地重新绑定(bind)一个名称(而不是复制)并且保证是原子的;你得到一个值或另一个。但是,可以像上面的属性一样覆盖对属性(或下标变量)的分配。在那种情况下,属性分配可能会中断。所以答案是属性分配通常是安全的,但如果它已被属性或 setattr 或类似的覆盖,则不是。

另外,如果被替换的旧值是一个带有析构函数的 Python 类,或者包含一个带有析构函数的 Python 类的东西,那么析构函数代码可以在赋值过程中运行。 Python 仍然会确保它自己的数据结构不会被破坏(所以你永远不会遇到段错误)但它不会为你自己做同样的事情。解决这个问题的明显方法是永远不要在任何类上定义 del

关于python - 线程安全的 Python 属性/特性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6952478/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com