次のシナリオがあります。
- マルチスレッドアプリケーション
- 私はスレッドの作成を管理していません。これはフレームワーク(この場合はセロリ)によって管理されます
- インスタンス化に費用がかかり、スレッドセーフではないオブジェクトがいくつかあります。それらをスレッドセーフにすることはオプションではありません。
- オブジェクトは複数の場所でインスタンス化できますが、すでに定義されている1つのスレッドで同じオブジェクトを再インスタンス化する場合は、オブジェクトを再利用する必要があります。
私は次のパターンを思いついた:
#!/usr/bin/env python
import threading
import time
class MyObj1:
def __init__(self, name):
self.name = name
local = threading.local()
def get_local_obj(key, create_obj, *pars, **kwargs):
d = local.__dict__
if key in d: obj = d[key]
else :
obj = create_obj(*pars, **kwargs)
d[key] = obj
return obj
class Worker(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
myobj1 = get_local_obj('obj1', MyObj1, (self.name))
for _ in xrange(3):
print myobj1.name
time.sleep(1)
def test():
ths = [Worker() for _ in xrange(2)]
for t in ths : t.start()
test()
これは単なるテストであるため、ここで私は自分でスレッドを作成していますが、実際のアプリケーションでは、スレッドを制御していません。
私が興味を持っているのは関数get_local_obj
です。いくつか質問があります。
- このロジックは、オブジェクトがスレッド間で共有されないことを保証しますか?
- このロジックは、オブジェクトがスレッド内で複数回インスタンス化されないことを保証しますか?
- このメモリリークはありますか?
- このアプローチについて一般的なコメントはありますか?上記で提案されたシナリオのより良い提案はありますか?
編集
明確にするために:私のアプリケーションはマルチスレイドですが、スレッドを作成しているのは私ではありません。フレームワークによって作成されたスレッド内で実行されるいくつかのオブジェクトを作成しているだけです。一部のオブジェクトはスレッドセーフではないため、スレッドごとに1回だけ作成する必要があります。したがってget_my_object
。
編集
local = threading.local()は、グローバルスコープで定義する必要があります。