私はDjangoサービスで動作している大規模なPythonアプリケーションを持っています。私は、このコンテキストマネージャを作成したように、特定の操作の許可検査をオフにする必要があります。doものの中で2.7 Pythonコンテキストマネージャをスレッドセーフにする方法
with override_tests:
do stuff
...
:アプリケーションの
class OverrideTests(object):
def __init__(self):
self.override = 0
def __enter__(self):
self.override += 1
# noinspection PyUnusedLocal
def __exit__(self, exc_type, exc_val, exc_tb):
self.override -= 1
assert not self.override < 0
@property
def overriding(self):
return self.override > 0
override_tests = OverrideTests()
様々な部分は、コンテキストマネージャを使用してテストをオーバライドすることができます上記のコンテキストマネージャは、異なる機能で複数回使用することができます。カウンタの使用はこれを制御し続け、スレッドが関与するまでうまくいくように見えます。
スレッドが関与すると、グローバルコンテキストマネージャが再利用され、その結果、テストが誤って上書きされる可能性があります。ここで
は、簡単なテストケースである - thread.start_new_thread(do_id,())
ラインが簡単なdo_it
に置き換えられますが示すように、見事に失敗した場合、これは正常に動作します:
def stat(k, expected):
x = '.' if override_tests.overriding == expected else '*'
sys.stdout.write('{0}{1}'.format(k, x))
def do_it_inner():
with override_tests:
stat(2, True)
stat(3, True) # outer with context makes this true
def do_it():
with override_tests:
stat(1, True)
do_it_inner()
stat(4, False)
def do_it_lots(ntimes=10):
for i in range(ntimes):
thread.start_new_thread(do_it,())
私はそれぞれになるように、このコンテキストマネージャスレッドが安全に行うことができますどのようにPythonスレッドは、リエントラントであっても一貫して使用されますか?
コンテキストマネージャを1つ作成せずに、代わりに「OverrideTests()」を使用して、毎回別のインスタンスを作成しましたか? – BrenBarn
テストコードは、テストを適用するかどうかを知るために、コンテキストマネージャシングルトンの「グローバル値」にアクセスします。これはwithステートメントの直後のコンテキストにはありません。テストメソッドに 'override_tests.overriding:return True'があればオーバーライドされます。複数のコンテキストマネージャインスタンスがある場合、私はそれを行うことができません。 –
グローバルな状態の変化に依存しているものは、スレッドに関する問題に遭遇します。ここで構造全体を再考する必要があるかもしれないように思えます。その種のグローバルフラグをチェックすることによって行動を変える機能を持つことはあまり堅牢ではありません。たとえば、すべてのテスト関数をクラスに入れて、各インスタンスが独自のオーバーライドステータスを格納し、スレッドごとにそのクラスの新しいインスタンスを作成することができます。 – BrenBarn