如何包装Python迭代器以使其线程安全?

时间:2012-11-19 15:20:10

标签: python iterator thread-safety python-2.7

因为有时它比围绕队列设计解决方案更实用,我想编写一个简单的包装器来使迭代器线程安全。到目前为止,我从these topics获得了灵感,并提出了两个想法:

想法1

class LockedIterator(object):
    def __init__(self, it):
        self._lock = threading.Lock()
        self._it = it.__iter__()
        if hasattr(self._it, 'close'):
            def close(self):
                with self._lock:
                    self._it.close()
            self.__setattr__('close', close)

    def __iter__(self):
        return self

    def next(self):
        with self._lock:
            return self._it.next()

我不喜欢它,如果我必须指定所有可能的方法它会变得有点冗长 - 好吧,我不能 - 比如发电机的特殊情况。此外,我可能还有一些其他迭代器,甚至更具体的方法现在已被隐藏。

创意2

class LockedIterator(object):
    def __init__(self, it):
        self._lock = threading.Lock()
        self._it = it.__iter__()

    def __getattr__(self, item):
        attr = getattr(self._it, item)
        if callable(attr):
            def hooked(*args, **kwargs):
                with self._lock:
                    return attr(*args, **kwargs)
            setattr(self, item, hooked)
            return hooked

这更简洁,但它只能拦截调用,而不是直接的属性更改。 (现在隐藏这些属性以防止出现问题。)更重要的是,它使得Python不再将我的对象识别为迭代器!

为所有迭代器(甚至更好的:所有对象)使这个工作的最佳方法是什么,而不会创建漏洞抽象?当没有必要时我不太担心锁定,但是如果你能想出一个解决这个问题的解决方案,那太好了!

1 个答案:

答案 0 :(得分:6)

首先,你知道the GIL吗?尝试编写多线程Python通常比使用简单的单线程版本的运行时间更慢。

您第一次尝试访问迭代器线程安全似乎是非常合理的。您可以使用生成器使其更具可读性:

def locked_iter(it):
    it = iter(it)
    lock = threading.Lock()
    while True:
        try:
            with lock:
                value = next(it)
        except StopIteration:
            return
        yield value