Pythonはfunctoolsを用いて注釈同期方法を実現する

1996 ワード

PythonではJavaで使用されるsynchronizedキーワードのような同期方法はないので、Pythonでは同期方法を実装するには、通常threading.Lock()を使用して実装します.関数に入る場所でロックを取得し、関数を出すときにロックを解放すると、実装コードがよく見えなくなります.また、ネット上では他のいくつかの実現方法が示されていますが、美しく見えません.
今日、プロジェクトをしていたとき、functoolsで注釈による表記方法を同期方法として実現できるかどうかふと考えました.
まず、自分のクラスにロックオブジェクトがあり、クラスの初期化時にこのロックオブジェクトを初期化する必要があります.たとえば、次のようにします.
class MyWorker(object):

    def __init__(self):
        self.lock = threading.Lock()
        ...

    ...

次にsynchronized関数を作成します.この関数は、次のように、特定のオブジェクトの特定のメソッドを装飾し、取得/解放ロックの間にメソッドを配置して実行します.
def synchronized(func):
    @functools.wraps(func)
    def wrapper(self, *args, **kwargs):
        with self.lock:
            return func(self, *args, **kwargs)
    return wrapper

最後に、同期を使用する必要があるメソッドに@synchronizedを使用して、標準的なメソッドは同期メソッドです.たとえば、次のようにします.
@synchronized
def test(self):
    ...

以下は、参照用に完全な例です.
import threading
import functools
import time


def synchronized(func):
    @functools.wraps(func)
    def wrapper(self, *args, **kwargs):
        with self.lock:
            return func(self, *args, **kwargs)
    return wrapper


class MyWorker(object):

    def __init__(self):
        self.lock = threading.Lock()
        self.idx = 0

    @synchronized
    def test1(self):
        for i in range(1, 11):
            self.idx = self.idx + 1
            print "Test1: " + str(self.idx)
            time.sleep(1)

    @synchronized
    def test2(self):
        for i in range(1, 11):
            self.idx = self.idx + 1
            print "Test2: " + str(self.idx)
            time.sleep(1)

    @synchronized
    def test3(self):
        for i in range(1, 11):
            self.idx = self.idx + 1
            print "Test3: " + str(self.idx)
            time.sleep(1)

worker = MyWorker()

threading.Thread(target=worker.test1).start()
threading.Thread(target=worker.test2).start()
threading.Thread(target=worker.test3).start()