我是 python 新手,目前正在尝试学习线程。我厌倦了使用锁来使我的资源成为线程安全的,因为它们本身并不与资源绑定,所以每次我的代码与资源交互时,我一定会忘记获取和/或释放它们。相反,我希望能够“包装”(或装饰?)一个对象,以便它的所有方法和属性 getter/setter 都是原子的。像这样的东西:
state = atomicObject(dict())
# the following is atomic/thread-safe
state["some key"] = "some value"
这可能吗?如果是这样,实施它的“最佳实践”方式是什么?
编辑:如何使内置容器(集合、字典、列表)线程安全?. 然而; 正如 abarnert 和 jsbueno 都证明的那样,我提出的解决方案(自动化锁)通常不是一个好主意,因为确定原子操作的适当粒度需要一些智能,并且可能很难(或不可能)正确地自动化。
问题仍然存在,锁没有以任何方式绑定到它们要保护的资源,所以我的新问题是:将锁与对象关联的好方法是什么?
提议的解决方案#2:我想可能有一种方法可以将锁绑定到一个对象,这样在不首先获取锁的情况下尝试访问该对象会引发错误,但我可以看到这会变得多么棘手。
编辑:以下代码与问题不太相关。我发布它是为了证明我曾尝试自己解决问题,但在发布此问题之前迷路了。
作为记录,我编写了以下代码,但它不起作用:
import threading
import types
import inspect
class atomicObject(object):
def __init__(self, obj):
self.lock = threading.RLock()
self.obj = obj
# keep track of function handles for lambda functions that will be created
self.funcs = []
# loop through all the attributes of the passed in object
# and create wrapped versions of each attribute
for name in dir(self.obj):
value = getattr(self.obj, name)
if inspect.ismethod(value):
# this is where things get really ugly as i try to work around the
# limitations of lambda functions and use eval()... I'm not proud of this code
eval("self.funcs.append(lambda self, *args, **kwargs: self.obj." + name + "(*args, **kwargs))")
fidx = str(len(self.funcs) - 1)
eval("self." + name + " = types.MethodType(lambda self, *args, **kwargs: self.atomize(" + fidx + ", *args, **kwargs), self)")
def atomize(self, fidx, *args, **kwargs):
with self.lock:
return self.functions[fidx](*args, **kwargs)
我可以创建一个 atomicObject(dict()),但是当我尝试向对象添加一个值时,我得到了错误;“atomicObject 不支持项目分配”。