[英]Using Pyramid events and multithreading
我想将事件订阅/通知与多线程一起使用。 听起来它应该在理论上起作用,并且文档不包含任何警告。 事件应该是同步的,所以也不能延迟。
但在实践中,当我通知主线程时,什么也没有出现:
def run():
logging.config.fileConfig(sys.argv[1])
with bootstrap(sys.argv[1]) as env:
get_current_registry().notify(FooEvent()) # <- works
Thread(target=thread).start() # <- doesn't work
def thread():
get_current_registry().notify(FooEvent())
预计这不会起作用吗? 还是我做错了什么?
我也尝试了建议的解决方案。 它不会打印预期的事件。
class Foo:
pass
@subscriber(Foo)
def metric_report(event):
print(event)
def run():
with bootstrap(sys.argv[1]) as env:
def foo(env):
try:
with env:
get_current_registry().notify(Foo())
except Exception as e:
print(e)
t = Thread(target=foo, args=(env,))
t.start()
t.join()
get_current_registry()
在处理请求或配置时尝试访问线程局部变量 Pyramid 寄存器,以告诉线程 Pyramid 应用程序当前在该线程中处于活动状态。 这里的问题是get_current_registry()
总是返回一个注册表,而不是您想要的注册表,所以很难看出它为什么不起作用。
生成新线程时,您需要将 Pyramid 应用程序注册为当前线程本地。 最好的方法是使用pyramid.scripting.prepare
。 “简单”的方法就是在你的线程中再次运行引导程序。 不过,我会展示“正确”的方式。
def run():
pyramid.paster.setup_logging(sys.argv[1])
get_current_registry().notify(FooEvent()) # doesn't work, just like in the thread
with pyramid.paster.bootstrap(sys.argv[1]) as env:
registry = env['registry']
registry.notify(FooEvent()) # works
get_current_registry().notify(FooEvent()) # works
Thread(target=thread_main, args=(env['registry'],)).start()
def thread_main(registry):
registry.notify(FooEvent()) # works, but threadlocals are not setup if other code triggered by this invokes get_current_request() or get_current_registry()
# so let's setup threadlocals
with pyramid.scripting.prepare(registry=registry) as env:
registry.notify(FooEvent()) # works
get_current_registry().notify(FooEvent()) # works
pyramid.scripting.prepare
是 bootstrap 在后台使用的,并且比多次运行 bootstrap 更有效,因为它共享注册表和所有应用程序配置,而不是制作应用程序的全新副本。
仅仅是“with”上下文仅适用于 Thread() create 语句而不传播到 thread() 方法。 即在“get_current_registry”调用具有“with”环境上下文的情况下,但这个“with”上下文不会传播到线程运行“get_current_registry”的位置。 因此,您需要将 env 传播到 thread() - 可能通过创建一个简单的可运行 class 来获取 init 方法中的 env。
class X:
def __init__(self,env):
self.env = env
def __call__(self):
with self.env:
get_current_registry().notify(FooEvent())
return
def run():
logging.config.fileConfig(sys.argv[1])
with bootstrap(sys.argv[1]) as env:
get_current_registry().notify(FooEvent())
Thread(target=X(env)).start()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.