【问题标题】:Await future/coroutine inside event loop; outside coroutine在事件循环中等待未来/协程;外部协程
【发布时间】:2020-02-26 10:30:57
【问题描述】:

我有一些具有这种结构的代码:

def my_callback():
    loop = asyncio.get_event_loop()
    return loop.run_until_complete(my_coroutine_2())

async def my_coroutine_2():
    return await my_stuff.some_future

async def my_coroutine():
    not_my_code.library_function(my_callback)

library_function 调用的my_callback 内部,我需要访问和运行协程代码。

但是,run_until_complete 会产生错误:Event loop already running!

是否有可能完成上面的描述?

也就是说,是否有一个普通的函数调用会导致事件循环暂停当前正在执行的任何协程(即loop.run_until_complete()的调用者),并继续执行其他协程(包括传递给@987654327的那个) @) 直到请求的协程完成,在这种情况下普通函数解除阻塞?

我认为线程可能会有所帮助,但据我了解,所有协程都必须属于同一个线程。

我该怎么做?有可能吗?

【问题讨论】:

    标签: python-3.x asynchronous concurrency python-asyncio coroutine


    【解决方案1】:

    假设外部库是线程安全的,您可以使用run_in_executor 在线程外调用它的函数。在等待函数完成时,当前的协程会被阻塞,但事件循环会继续运行。

    当您的回调从另一个线程调用时,它可以使用run_coroutine_threadsafe 将协程提交到(仍然功能齐全的)事件循环,并将结果报告回库:

    async def my_coroutine():
        loop = asyncio.get_event_loop()
        await loop.run_in_executor(None, not_my_code.library_function,
                                   lambda: my_callback(loop))
    
    def my_callback(loop):
        return asyncio.run_coroutine_threadsafe(my_coroutine_2(), loop)
    

    【讨论】:

    • 嗯,这确实回答了问题!不幸的是,为了简化示例,我更改了一个重要的细节:实际上是外部库启动循环并调用 library_function;所以我没有选择改变它的调用方式。所以你的答案是正确的,但对我没有帮助!不过我会接受的。
    • @trbabb 您的协程需要做的事情是否与库运行的协程相关?换句话说,如果两者运行在不同且不相关的事件循环中会不会有问题?
    • ——我的协程等待库循环中产生的协程/期货。
    • @trbabb 现在这真是个泡菜。总结一下:你有一个使用 asyncio 实现的库,它坚持在同步代码内部自行运行事件循环,并从它运行的事件循环中调用 sync 回调函数并期望回复?在同步回调中​​,您需要等待库生成的其他任务吗?如果是这样,恐怕 asyncio 没有提供这样做的方法,因为它明确禁止嵌套事件循环,并且您不能使用多个事件循环。听起来图书馆要么设计得很糟糕,要么你在滥用它。
    • 库是 uwsgi 在 --asyncio 模式。 ...没有评论它的设计质量/使用它有多少“乐趣”。 :|
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-26
    • 1970-01-01
    • 2023-03-19
    • 2020-05-15
    • 2021-10-22
    • 2019-12-15
    • 2021-10-15
    相关资源
    最近更新 更多