当循环运行时,如何运行协同例程并等待同步函数产生的结果? [英] How to run a coroutine and wait it result from a sync func when the loop is running?

查看:24
本文介绍了当循环运行时,如何运行协同例程并等待同步函数产生的结果?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类似愚弄的代码:

def render():
    loop = asyncio.get_event_loop()

    async def test():
        await asyncio.sleep(2)
        print("hi")
        return 200

    if loop.is_running():
        result = asyncio.ensure_future(test())
    else:
        result = loop.run_until_complete(test())

loop没有运行时非常简单,只需使用loop.run_until_complete,它会返回coro结果,但是如果循环已经在运行(我的阻塞代码运行在已经在运行循环的应用程序中),我不能使用loop.run_until_complete,因为它会引发异常;当我调用asyncio.ensure_future时,任务会被调度并运行,但我想在那里等待结果,有人知道怎么做吗?文档不太清楚如何执行此操作。

我尝试在coro中传递一个concurrent.futures.Future调用set_result,然后在我的阻塞代码上调用Future.result(),但它不起作用,它在那里阻塞,并且不让任何其他东西运行。如有任何帮助,我们将不胜感激。

推荐答案

要使用建议的设计实现runner,您需要一种方法来单步执行在其中运行的回调的事件循环。Asyncioexplicitly forbids递归事件循环,因此此方法是死胡同。

考虑到该约束,您有两个选择:

  1. 使render()本身成为协程;
  2. 在与运行异步事件循环的线程不同的线程中执行render()(及其调用方)。

假设不存在#1,您可以实现render()的#2变体,如下所示:

def render():
    loop = _event_loop  # can't call get_event_loop()

    async def test():
        await asyncio.sleep(2)
        print("hi")
        return 200

    future = asyncio.run_coroutine_threadsafe(test(), loop)
    result = future.result()
请注意,您不能在render中使用asyncio.get_event_loop(),因为没有(也不应该)为该线程设置事件循环。相反,派生运行器线程的代码必须调用asyncio.get_event_loop()并将其发送到线程,或者只是将其保留在全局变量或共享结构中。

这篇关于当循环运行时,如何运行协同例程并等待同步函数产生的结果?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆