繁体   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