在异步函数内的同步函数内运行异步函数

Posted

技术标签:

【中文标题】在异步函数内的同步函数内运行异步函数【英文标题】:run async function inside sync function inside async function 【发布时间】:2021-08-19 09:11:35 【问题描述】:

这是我遇到的问题的简化方案。

import asyncio

async def c():
    print("yes")

def b():
    asyncio.run(c())

async def a():
    b()

asyncio.run(a())

我希望程序打印“是”。但是,我得到了这个:

Traceback (most recent call last):
  File [redacted], line 12, in <module>
    asyncio.run(a())
  File "/usr/lib64/python3.7/asyncio/runners.py", line 43, in run
    return loop.run_until_complete(main)
  File "/usr/lib64/python3.7/asyncio/base_events.py", line 579, in run_until_complete
    return future.result()
  File [redacted], line 10, in a
    b()
  File [redacted], line 7, in b
    asyncio.run(c())
  File "/usr/lib64/python3.7/asyncio/runners.py", line 34, in run
    "asyncio.run() cannot be called from a running event loop")
RuntimeError: asyncio.run() cannot be called from a running event loop
sys:1: RuntimeWarning: coroutine 'c' was never awaited

你认为解决这个问题的方法是什么?

(另外,这可以使用纯异步来完成吗?)

【问题讨论】:

为什么需要这样做?您的用例是什么,因为它们可能是更好的解决方案。 对此没有合适的解决方案。即使你在技术上可以做到这一点,你真的,真的不应该 - 它会阻塞外部事件循环,即使在最好的情况下也会使异步的任何好处无效。 请edit您的问题澄清问题的约束。现在,“正确”的解决方案就是删除 b。 b是否需要C的返回值? b 可以变成异步函数吗? c 必须在 b 期间完成吗? b是否需要在主线程中运行,c是否需要在主事件循环中运行? 【参考方案1】:

不要在同一个程序中调用 asyncio.run() 两次。相反,一旦事件循环运行,创建一个任务并等待它。同步函数可以创建一个新任务但不能等待它;它可以将它作为等待返回。然后异步调用函数可以执行等待。

import asyncio

async def c():
    print("yes")

def b():
    return asyncio.create_task(c())

async def a():
    task = b()
    await task

asyncio.run(a())

>>>yes

【讨论】:

这里不需要任务。 b 可以直接返回 c()。 是的。但是除非在某处创建了第二个任务,否则根本不需要 asyncio。这似乎是问题所在,因为第二次尝试调用 run()。

以上是关于在异步函数内的同步函数内运行异步函数的主要内容,如果未能解决你的问题,请参考以下文章

js事件循环

异步函数停止同步函数

js事件循环机制

在python中等待多个异步函数

C#有异步函数调用同步函数或同步函数调用异步函数

学习日记0910线程池与进程池 同步调用与异步调用 函数回调