簡體   English   中英

使用 Pyramid 事件和多線程

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM