栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

如何使内置容器(集合,字典,列表)具有线程安全性?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

如何使内置容器(集合,字典,列表)具有线程安全性?

您可以使用Python的元编程工具来完成此任务。(注意:写得很快,没有经过全面测试。)我更喜欢使用类装饰器。

我还认为您 可能 需要锁定多个对象

add
remove
设置一个线程安全的集合,但是我不确定。我将忽略该问题,仅关注您的问题。

还应考虑委派(代理)是否比子类更好。包装对象是Python中的常用方法。

最后,没有元编程的“魔杖”会神奇地向任何可变的Python集合添加细粒度的锁定。最安全的方法是使用锁定 任何
方法或属性访问

RLock
,但这是非常粗糙且缓慢的,并且可能仍不能保证您的对象在所有情况下都是线程安全的。(例如,您可能有一个集合,该集合操作另一个可访问其他线程的非线程安全对象。)您确实确实需要检查每个数据结构,并考虑哪些操作是原子操作或需要锁,以及哪些方法可能调用其他方法。使用相同的锁(即死锁本身)。

就是说,这里有一些以抽象顺序递增的方式供您使用:

代表团

class LockProxy(object):    def __init__(self, obj):        self.__obj = obj        self.__lock = RLock()        # RLock because object methods may call own methods    def __getattr__(self, name):        def wrapped(*a, **k): with self.__lock:     getattr(self.__obj, name)(*a, **k)        return wrappedlockedset = LockProxy(set([1,2,3]))

上下文管理器

class LockedSet(set):    """A set where add(), remove(), and 'in' operator are thread-safe"""    def __init__(self, *args, **kwargs):        self._lock = Lock()        super(LockedSet, self).__init__(*args, **kwargs)    def add(self, elem):        with self._lock: super(LockedSet, self).add(elem)    def remove(self, elem):        with self._lock: super(LockedSet, self).remove(elem)    def __contains__(self, elem):        with self._lock: super(LockedSet, self).__contains__(elem)

装饰器

def locked_method(method):    """Method decorator. Requires a lock object at self._lock"""    def newmethod(self, *args, **kwargs):        with self._lock: return method(self, *args, **kwargs)    return newmethodclass DecoratorLockedSet(set):    def __init__(self, *args, **kwargs):        self._lock = Lock()        super(DecoratorLockedSet, self).__init__(*args, **kwargs)    @locked_method    def add(self, *args, **kwargs):        return super(DecoratorLockedSet, self).add(elem)    @locked_method    def remove(self, *args, **kwargs):        return super(DecoratorLockedSet, self).remove(elem)

类装饰器

我认为这是抽象方法最清晰,最容易理解的方法,因此我对其进行了扩展,以允许它指定要锁定的方法和一个锁定对象工厂。

def lock_class(methodnames, lockfactory):    return lambda cls: make_threadsafe(cls, methodnames, lockfactory)def lock_method(method):    if getattr(method, '__is_locked', False):        raise TypeError("Method %r is already locked!" % method)    def locked_method(self, *arg, **kwarg):        with self._lock: return method(self, *arg, **kwarg)    locked_method.__name__ = '%s(%s)' % ('lock_method', method.__name__)    locked_method.__is_locked = True    return locked_methoddef make_threadsafe(cls, methodnames, lockfactory):    init = cls.__init__    def newinit(self, *arg, **kwarg):        init(self, *arg, **kwarg)        self._lock = lockfactory()    cls.__init__ = newinit    for methodname in methodnames:        oldmethod = getattr(cls, methodname)        newmethod = lock_method(oldmethod)        setattr(cls, methodname, newmethod)    return cls@lock_class(['add','remove'], Lock)class ClassDecoratorLockedSet(set):    @lock_method # if you double-lock a method, a TypeError is raised    def frobnify(self):        pass

使用覆盖属性访问
__getattribute__

class AttrLockedSet(set):    def __init__(self, *args, **kwargs):        self._lock = Lock()        super(AttrLockedSet, self).__init__(*args, **kwargs)    def __getattribute__(self, name):        if name in ['add','remove']: # note: makes a new callable object "lockedmethod" on every call # best to add a layer of memoization lock = self._lock def lockedmethod(*args, **kwargs):     with lock:         return super(AttrLockedSet, self).__getattribute__(name)(*args, **kwargs) return lockedmethod        else: return super(AttrLockedSet, self).__getattribute__(name)

动态添加包装方法
__new__

class NewLockedSet(set):    def __new__(cls, *args, **kwargs):        # modify the class by adding new unbound methods        # you could also attach a single __getattribute__ like above        for membername in ['add', 'remove']: def scoper(membername=membername):     # You can also return the function or use a class     def lockedmethod(self, *args, **kwargs):         with self._lock:  m = getattr(super(NewLockedSet, self), membername)  return m(*args, **kwargs)     lockedmethod.__name__ = membername     setattr(cls, membername, lockedmethod)        self = super(NewLockedSet, cls).__new__(cls, *args, **kwargs)        self._lock = Lock()        return self

动态添加包装方法
__metaclass__

def _lockname(classname):    return '_%s__%s' % (classname, 'lock')class LockedClass(type):    def __new__(mcls, name, bases, dict_):        # we'll bind these after we add the methods        cls = None        def lockmethodfactory(methodname, lockattr): def lockedmethod(self, *args, **kwargs):     with getattr(self, lockattr):         m = getattr(super(cls, self), methodname)         return m(*args,**kwargs) lockedmethod.__name__ = methodname return lockedmethod        lockattr = _lockname(name)        for methodname in ['add','remove']: dict_[methodname] = lockmethodfactory(methodname, lockattr)        cls = type.__new__(mcls, name, bases, dict_)        return cls    def __call__(self, *args, **kwargs):        #self is a class--i.e. an "instance" of the LockedClass type        instance = super(LockedClass, self).__call__(*args, **kwargs)        setattr(instance, _lockname(self.__name__), Lock())        return instanceclass metaLockedSet(set):    __metaclass__ = LockedClass

动态创建的元类

def LockedClassmetaFactory(wrapmethods):    class LockedClass(type):        def __new__(mcls, name, bases, dict_): # we'll bind these after we add the methods cls = None def lockmethodfactory(methodname, lockattr):     def lockedmethod(self, *args, **kwargs):         with getattr(self, lockattr):  m = getattr(super(cls, self), methodname)  return m(*args,**kwargs)     lockedmethod.__name__ = methodname     return lockedmethod lockattr = _lockname(name) for methodname in wrapmethods:     dict_[methodname] = lockmethodfactory(methodname, lockattr) cls = type.__new__(mcls, name, bases, dict_) return cls        def __call__(self, *args, **kwargs): #self is a class--i.e. an "instance" of the LockedClass type instance = super(LockedClass, self).__call__(*args, **kwargs) setattr(instance, _lockname(self.__name__), Lock()) return instance    return LockedClassclass metaFactoryLockedSet(set):    __metaclass__ = LockedClassmetaFactory(['add','remove'])

我敢打赌,现在使用一个简单明了的方法

try...finally
看起来还不错,对吧?

读者的练习:

Lock()
使用这些方法中的任何一种,让调用者传递他们自己的对象(依赖注入)。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/455682.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号