我想把事件订阅通知和多线程一起使用。这听起来好像只是理论上的工作,文档中也没有任何警告。事件应该是同步的,所以也不会延迟。
但实际上,当我在主线程外通知时,没有任何东西进来。
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应用注册为当前线程local。最好的方法是使用 pyramid.scripting.prepare
. 简单的方法就是在你的线程中重新运行bootstrap。但我会告诉你 "正确 "的方法。
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()创建语句?只是 也就是说,在这个例子中,'get_current_registry'调用有'with'env上下文,但是这个'with'上下文不会传播到线程运行'get_current_registry'的地方。所以你需要将env传播到线程()--也许通过创建一个简单的可运行类,在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()