我有一个大型python应用程序,它运行在Django服务上。我需要关闭某些操作的权限测试,所以我创建了这个上下文管理器:
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()然后,应用程序的各个部分可以使用上下文管理器覆盖测试:
with override_tests:
do stuff
...在do中,上面的上下文管理器可以在不同的函数中多次使用。计数器的使用控制住了这一切,而且它似乎运转良好.直到线索介入。
一旦涉及到线程,全局上下文管理器就会被重用,因此,测试可能会被错误地覆盖。
下面是一个简单的测试用例--如果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线程中,即使它是可重用的,它也可以被一致使用?
发布于 2015-11-02 05:03:19
下面是一种可行的方法:使您的OverrideTests类成为threading.local的子类。为了安全起见,您应该在您的__init__中调用超类__init__ (尽管它似乎工作,即使您没有):
class OverrideTests(threading.local):
def __init__(self):
super(OverrideTests, self).__init__()
self.override = 0
# rest of class same as before
override_tests = OverrideTests()然后:
>>> do_it_lots()
1.1.1.2.2.1.1.1.1.1.1.3.3.2.2.2.2.2.2.4.4.3.1.3.3.3.3.4.3.2.4.4.2.4.3.4.4.4.3.4.但是,我不会把钱花在这种情况下,尤其是如果您的实际应用程序比您在这里展示的示例更复杂的话。最终,你真的应该重新考虑你的设计。在您的问题中,您关注的是如何“使上下文管理器线程安全”。但真正的问题不仅在于上下文管理器,还在于您的函数(在您的示例中是stat)。stat依赖全局状态(全局override_tests),它在线程环境中本质上是脆弱的。
https://stackoverflow.com/questions/33407515
复制相似问题