我试图创建一个@synchronized包装器,它为每个对象创建一个锁,并使方法调用线程安全。我只能在可以访问包装方法中方法的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)令人困惑的是,传递给decorator的func参数在传递给包装生成器之前更改了类型。这似乎是粗鲁和不必要的。为什么会这样?
(2)有没有什么装饰魔法可以让我对一个对象mutexd进行方法调用(即每个对象一个锁,而不是每个类一个锁)。
更新:有很多@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
这可能吗?
由于decorator是在函数定义时应用的,因此无法在修饰时获取
self
。还不存在self
;实际上,类还不存在。如果您愿意将锁存储在实例上(这可以说是每个实例值应该存储的地方),那么这可能会:
您还可以在
__init__()
方法中的某个基类上生成锁,并以相同的方式将其存储在实例上。这简化了您的decorator,因为您不必检查self._lock
属性的存在性。不是的!相反,当函数对象(和其他描述符)的方法被调用时,函数对象(和其他描述符)会产生它们的
__get__
结果,而结果就是方法对象!但是
class
的__dict__
中的内容始终是描述符——特别是函数对象!看看吧…:看到了吗?任何地方都没有方法对象!-)
因此,在装修的时候,也不要
im_self
在周围,你需要用你基于内省的另一种想法。阅读:
尤其是:
然后,
wrapt
模块包含此处描述的@synchronized
装饰器。全面的实施具有足够的灵活性:
以及类似上下文管理器的用法:
更多信息和示例,请参见:
还有一个会议讨论,您可以在以下位置观看如何实现:
相关问题 更多 >
编程相关推荐