8

キューを中心にソリューションを設計するよりも実用的な場合があるため、イテレータースレッドを安全にするための単純なラッパーを作成したいと思います。これまでのところ、私はこれらの トピックからインスピレーションを得て、2つのアイデアを思いつきました。

アイデア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が私のオブジェクトをイテレーターとして認識しないようにすることです。

リークのある抽象化を作成せずに、すべてのイテレータ(またはさらに良い:すべてのオブジェクト)でこれを機能させるための最良の方法は何ですか?必要のないときにロックすることについてはあまり心配していませんが、それを回避する解決策を考え出すことができれば、素晴らしいです!

4

1 に答える 1

6

まず、 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
于 2012-11-19T20:11:05.367 に答える