[英]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.