我试图创建一个@synchronized包装器,为每个对象创建一个Lock,并使方法调用线程安全。如果我可以在包装方法中访问方法的method.im_self,我只能这样做。
class B:
def f(self): pass
assert inspect.ismethod( B.f ) # OK
assert inspect.ismethod( B().f ) # OK
print B.f # <unbound method B.f>
print B().f # <bound method B.f of <__main__.B instance at 0x7fa2055e67e8>>
def synchronized(func):
# func is not bound or unbound!
print func # <function f at 0x7fa20561b9b0> !!!!
assert inspect.ismethod(func) # FAIL
# ... allocate one lock per C instance
return func
class C:
@synchronized
def f(self): pass
(1)令人困惑的是传递给我的装饰器的func参数在传递给包装器生成器之前改变了类型。这似乎是粗鲁和不必要的。为什么会这样?
(2)是否有一些装饰魔术可以通过它来对互斥对象进行方法调用(即每个对象一个锁,而不是每个类)。
更新:@synchronized(lock)包装器有很多例子。但是,我真正想要的是@synchronized(self)。我可以解决它:
def synchronizedMethod(func):
def _synchronized(*args, **kw):
self = args[0]
lock = oneLockPerObject(self)
with lock: return func(*args, **kw)
return _synchronized
但是,因为它更有效率,我更喜欢:
def synchronizedMethod(func):
lock = oneLockPerObject(func.im_self)
def _synchronized(*args, **kw):
with lock: return func(*args, **kw)
return _synchronized
这可能吗?
答案 0 :(得分:19)
阅读:
,特别是:
然后wrapt
模块包含那里描述的@synchronized
装饰器。
完整的实施足够灵活:
@synchronized # lock bound to function1
def function1():
pass
@synchronized # lock bound to function2
def function2():
pass
@synchronized # lock bound to Class
class Class(object):
@synchronized # lock bound to instance of Class
def function_im(self):
pass
@synchronized # lock bound to Class
@classmethod
def function_cm(cls):
pass
@synchronized # lock bound to function_sm
@staticmethod
def function_sm():
pass
与上下文管理器一样使用:
class Object(object):
@synchronized
def function_im_1(self):
pass
def function_im_2(self):
with synchronized(self):
pass
更多信息和示例也可在以下网址找到:
还有一个会议演讲,您可以通过以下方式了解如何实施:
答案 1 :(得分:3)
(1)令人困惑的是传递给我的装饰器的func参数 在传递给包装器生成器之前更改类型。这个 看起来很粗鲁,没必要。为什么会这样?
没有!相反,当调用他们的方法时,函数对象(和其他描述符)会产生__get__
的结果 - 结果是方法对象!
但class
__dict__
中的所有内容始终是描述符 - 特别是函数对象!看看......:
>>> class X(object):
... def x(self): pass
...
>>> X.__dict__['x']
<function x at 0x10fe04e60>
>>> type(X.__dict__['x'])
<type 'function'>
请参阅?任何地方都没有方法对象根本! - )
因此,在装修时,两者都没有im_self
- 而且您需要采用基于内省的替代理念。
答案 2 :(得分:2)
装饰时无法获得self
,因为装饰器在功能定义时应用。还没有self
;事实上,类尚不存在。
如果您愿意将存储在实例上(可以说是每个实例值应该去的地方)那么这可能就是:
def synchronizedMethod(func):
def _synchronized(self, *args, **kw):
if not hasttr(self, "_lock"): self._lock = oneLockPerObject(self)
with self._lock: return func(self, *args, **kw)
return _synchronized
您还可以在某种基类上的__init__()
方法中生成锁,并以相同的方式将其存储在实例上。这简化了装饰器,因为您不必检查是否存在self._lock
属性。