代码之家  ›  专栏  ›  技术社区  ›  viraptor

使用Pyramid事件和多线程

  •  0
  • viraptor  · 技术社区  · 4 年前

    我想将事件订阅/通知与多线程一起使用。听起来它应该只是在理论上起作用,文档中没有任何警告。事件应该是同步的,所以也不能推迟。

    但在实践中,当我通知关闭主线程时,没有任何内容:

    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()
    
    0 回复  |  直到 4 年前
        1
  •  3
  •   Michael Merickel    4 年前

    get_current_registry() 正在处理请求或配置时尝试访问线程局部变量Pyramid寄存器,以告诉线程该线程中当前活动的Pyramid应用程序。这里的问题是 get_current注册表() 总是返回一个注册表,只是不是你想要的注册表,所以很难看出它为什么不起作用。

    生成新线程时,您需要将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
    

    吡喃酰胺.脚本.准备 这是bootstrap在幕后使用的,比多次运行bootstrap要高效得多,因为它共享注册表和所有应用程序配置,而不是为应用程序创建一个全新的副本。

        2
  •  2
  •   Mark Parris    4 年前

    只是'with'上下文适用于Thread()create语句吗 只有 并且不传播到thread()方法。也就是说,在有效的情况下,'get_current_registry'调用具有'with'env-context',但这个'with'上下文不会传播到线程运行`get_current-registry'的点。因此,您需要将env传递给thread()——也许是通过创建一个简单的可运行类,在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()