You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在同步函数中调用异步函数?RuntimeError问题求解

在同步函数中调用异步函数的正确实现方式

你的代码触发RuntimeError的核心原因有两个:

  1. 在func2中调用asyncio.get_event_loop()时,主线程还未启动任何事件循环(asyncio.run(func1())是在func2执行完毕后才运行的),此时获取循环会引发错误。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 22:18:30