可以创建一个@synchronized decorator来感知方法的对象吗?

2024-05-12 20:12:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图创建一个@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

这可能吗?


Tags: 对象方法selflockreturndefargsassert
3条回答

由于decorator是在函数定义时应用的,因此无法在修饰时获取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__()方法中的某个基类上生成锁,并以相同的方式将其存储在实例上。这简化了您的decorator,因为您不必检查self._lock属性的存在性。

(1) What's confusing is that the func parameter passed to my decorator changes type before it gets passed into the wrapper-generator. This seem is rude and unnecessary. Why does this happen?

不是的!相反,当函数对象(和其他描述符)的方法被调用时,函数对象(和其他描述符)会产生它们的__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在周围,你需要用你基于内省的另一种想法。

阅读:

尤其是:

然后,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

更多信息和示例,请参见:

还有一个会议讨论,您可以在以下位置观看如何实现:

相关问题 更多 >