私は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 はアイテムの割り当てをサポートしていません」。