6

私はPythonが初めてで、現在スレッドを学習しようとしています。ロックは本質的にリソースに関連付けられていないため、リソースをスレッドセーフにするためにロックを使用することにうんざりしています。代わりに、オブジェクトを「ラップ」(または装飾) して、オブジェクトのすべてのメソッドと属性ゲッター/セッターがアトミックになるようにしたいと考えています。このようなもの:

state = atomicObject(dict())

# the following is atomic/thread-safe
state["some key"] = "some value"

これは可能ですか?もしそうなら、それを実装する「ベストプラクティス」の方法は何ですか?

編集:上記の質問に対する適切な回答は、組み込みコンテナー (セット、辞書、リスト) をスレッドセーフにする方法で利用できますか? . でも; abarnert と jsbueno の両方が実証したように、私が提案したソリューション (ロックの自動化) は一般的には良い考えではありません。なぜなら、アトミック操作の適切な粒度を決定するにはある程度の知性が必要であり、適切に自動化するのは難しい (または不可能) 可能性が高いからです。

ロックが保護対象のリソースに何らかの方法でバインドされていないという問題がまだ残っているため、私の新しい質問は次のとおりです。ロックをオブジェクトに関連付ける良い方法は何ですか?

提案された解決策 #2: 最初にロックを取得せずにそのオブジェクトにアクセスしようとするとエラーがスローされるように、ロックをオブジェクトにバインドする方法があると思いますが、それがどのようにトリッキーになるかはわかります。

編集:次のコードは、質問とはあまり関係ありません。この質問を投稿する前に、自分で問題を解決しようとして迷子になったことを示すために投稿しました。

記録のために、次のコードを書きましたが、機能しません。

import threading    
import types
import inspect

class atomicObject(object):

    def __init__(self, obj):
        self.lock = threading.RLock()
        self.obj = obj

        # keep track of function handles for lambda functions that will be created
        self.funcs = []

        # loop through all the attributes of the passed in object
        # and create wrapped versions of each attribute
        for name in dir(self.obj):
            value = getattr(self.obj, name)
            if inspect.ismethod(value):
                # this is where things get really ugly as i try to work around the
                # limitations of lambda functions and use eval()... I'm not proud of this code
                eval("self.funcs.append(lambda self, *args, **kwargs: self.obj." + name + "(*args, **kwargs))")
                fidx = str(len(self.funcs) - 1)
                eval("self." + name + " = types.MethodType(lambda self, *args, **kwargs: self.atomize(" + fidx + ", *args, **kwargs), self)")

    def atomize(self, fidx, *args, **kwargs):
        with self.lock:
            return self.functions[fidx](*args, **kwargs)

atomicObject(dict()) を作成できますが、オブジェクトに値を追加しようとするとエラーが発生します。「atomicObject はアイテムの割り当てをサポートしていません」。

4

5 に答える 5

2

私はあなたの質問についていくつか考えましたが、それはトリッキーなものになるでしょう.Atomicクラスですべてのオブジェクトメソッドをプロキシする必要があるだけでなく、メソッドを適切に書くことでそれを行うことができます__getattribute__.また、プロキシされたオブジェクトに、元のオブジェクト クラスと同じ「マジック ダブル アンダースコア」メソッドを提供するクラスを提供する必要があります。つまり、プロキシされたクラスを動的に作成する必要があります。アトミック。

実行可能ですが、 Pythonは初めてなので、インタラクティブなプロンプトで実行できますimport this。表示されるいくつかのガイドライン/アドバイスの中で、「実装を説明するのが難しい場合は、それは悪い考えです。 """ :-)

Python でスレッドを使用すること は、一般的に悪い考えです。多くのブロッキング I/O を伴う準自明なコードを除いて - Python のスレッド化では、通常の Python コードがより多くの CPU コアを使用できないため、別のアプローチをお勧めします。たとえば、Python コードのスレッドは 1 つしかありません。一度に実行 - 「Python GIL」を検索して理由を確認してください - (例外として、Numpy 関数などの計算集約型のネイティブ コードに多くのコードが費やされている場合) .

しかし、そのために利用可能なさまざまなフレームワークの1つを使用して非同期呼び出しを使用するようにプログラムを作成するか、複数のコアを簡単に利用するには、multiprocessing代わりに使用しますthreading-これは基本的に「スレッド」ごとに1つのプロセスを作成します-必要ですその共有はすべて明示的に行う必要があります。

于 2013-04-12T01:45:03.067 に答える
0

この数年後に戻ってきます。コンテキスト マネージャーは、元の問題に対する理想的なソリューションだと思います。ロックがコンテキスト管理をサポートしていることは知っていますが、ロックとロックされたリソースの間の関係を強制するという問題が残っています。代わりに、次のようなものが良いと思います。

class Locked:
    def __init__(self, obj):
        super().__init__()
        self.__obj = obj
        self.lock = threading.RLock()

    def __enter__(self):
        self.lock.acquire()
        return self.__obj

    def __exit__(self, *args, **kwargs):
        self.lock.release()


guard = Locked(dict())

with guard as resource:
    do_things_with(resource)
于 2016-06-03T05:37:06.670 に答える