如何在同步函数中调用异步函数?RuntimeError问题求解
在同步函数中调用异步函数的正确实现方式
你的代码触发RuntimeError的核心原因有两个:
- 在
func2中调用asyncio.get_event_loop()时,主线程还未启动任何事件循环(asyncio.run(func1())是在func2执行完毕后才运行的),此时获取循环会引发错误。 asyncio.run_coroutine_threadsafe的设计目的是跨线程向正在运行的事件循环提交协程,并非同一线程内同步调用异步函数的正确方式。
可以实现同步函数调用异步函数,根据不同场景有以下几种正确实现方式:
场景1:同步函数与异步代码在同一线程
方式1:后台执行异步函数(不阻塞同步函数)
如果当前线程已经有运行中的事件循环,可直接将异步函数提交到循环中后台执行,不阻塞同步函数的流程:
import asyncio import datetime import time async def func1(): print(f'{datetime.now().time()} func1 start') await asyncio.sleep(1) print(f'{datetime.now().time()} func1 over') async def func21(): print(f'{datetime.now().time()} func21 start') await asyncio.sleep(1) print(f'{datetime.now().time()} func21 over') def func2(): print(f'{datetime.now().time()} func2 start') time.sleep(1) # 获取当前运行中的事件循环,提交协程后台执行 loop = asyncio.get_running_loop() loop.create_task(func21()) print(f'{datetime.now().time()} func2 over') async def main(): for i in range(3): func2() await func1() if __name__ == '__main__': asyncio.run(main())
方式2:阻塞等待异步函数完成
如果需要同步等待异步函数执行完毕再继续同步流程,可直接在同步函数中调用asyncio.run():
def func2_blocking(): print(f'{datetime.now().time()} func2 start') time.sleep(1) # 阻塞直到异步函数执行完成 asyncio.run(func21()) print(f'{datetime.now().time()} func2 over')
场景2:同步函数在其他线程调用异步函数
如果同步函数运行在独立线程,需要向主线程或其他线程的事件循环提交异步任务,可使用asyncio.run_coroutine_threadsafe,但必须确保目标事件循环处于运行状态:
import asyncio import datetime import time import threading # 创建事件循环并在独立线程中运行 loop = asyncio.new_event_loop() def run_event_loop(): asyncio.set_event_loop(loop) loop.run_forever() # 启动守护线程运行事件循环 threading.Thread(target=run_event_loop, daemon=True).start() async def func1(): print(f'{datetime.now().time()} func1 start') await asyncio.sleep(1) print(f'{datetime.now().time()} func1 over') async def func21(): print(f'{datetime.now().time()} func21 start') await asyncio.sleep(1) print(f'{datetime.now().time()} func21 over') def func2_threaded(): print(f'{datetime.now().time()} func2 start') time.sleep(1) # 向其他线程的事件循环提交协程 future = asyncio.run_coroutine_threadsafe(func21(), loop) # 若需等待结果,取消下方注释(会阻塞同步函数) # future.result() print(f'{datetime.now().time()} func2 over') if __name__ == '__main__': for i in range(3): func2_threaded() asyncio.run(func1())
总结
- 同一线程内优先使用
asyncio.get_running_loop().create_task()(后台执行)或asyncio.run()(阻塞等待)。 - 跨线程调用必须确保目标事件循环正在运行,使用
asyncio.run_coroutine_threadsafe()提交任务。
内容的提问来源于stack exchange,提问作者f1msch
相关产品推荐
相关产品推荐

