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

为何无法多次调用asyncio.run()?如何异步运行Graph API相关函数

问题描述

我正在编写脚本,使用Microsoft Graph API连接并查询Azure Entra ID中的用户数据。需要两个异步函数:一个获取指定组的用户,另一个根据用户ID获取其显示名称。单独用asyncio.run()运行任意一个都正常,但同时运行两个时第二个函数报错,搞不清第二次调用asyncio.run()失败的原因。

主脚本中调用第一个函数的代码:

async def get_all_group_members():
    memberListAll = []
    for group in groupList:
        # print(f"We are trying to run group {group}")
        results = await gq.get_group_user(group['GroupID'], graphServiceClient)
        memberDict = {"GroupName":group["GroupName"], "GroupID":group["GroupID"], "MemberList":results}
        memberListAll.append(memberDict)
    return memberListAll
results = asyncio.run(get_all_group_members())

get_group_user的定义:

memberList = []
members = await graphServiceClient.groups.by_group_id(groupID).members.get()
if members and members.value:
    for member in members.value:
        user = await graphServiceClient.users.by_user_id(member.id).get()
        if user:
            memberList.append(user.display_name)
return memberList

主脚本中调用第二个函数的代码:

async def get_user_name():
    results = await gq.get_user_by_id(member=member,graphServiceClient=graphServiceClient)
    return results

results2 = asyncio.run(get_user_name())

get_user_by_id的定义:

user = await graphServiceClient.users.by_user_id(member).get()
print(user)

单独运行任意一个函数都正常,同时运行第二个就失败,求问原因和修改方案。


问题原因与解决方法

为什么多次调用asyncio.run()会失败?

asyncio.run()的设计是创建并管理一个全新的事件循环,运行传入的协程直到完成后自动关闭事件循环。第一次调用时,它初始化循环、执行协程,之后关闭整个循环;第二次调用时,要么单线程环境下默认策略无法重建有效循环,要么你的graphServiceClient已绑定到第一次的循环资源上,循环关闭后客户端连接失效,导致报错。另外,asyncio.run()本身是作为异步程序的入口点设计的,不推荐多次调用。

修改方案

方案1:合并协程到同一事件循环(推荐)

创建一个主协程,将两个任务串行或并行执行,仅调用一次asyncio.run()启动主协程。

串行执行(按顺序运行)

async def main():
    # 先执行组成员获取逻辑
    results = await get_all_group_members()
    # 再执行用户名称获取逻辑
    results2 = await get_user_name()
    return results, results2

# 仅调用一次asyncio.run()
final_results, final_results2 = asyncio.run(main())

并行执行(无依赖时提升效率)

如果两个任务没有先后依赖,用asyncio.gather()让它们同时运行:

async def main():
    # 同时启动两个协程
    results, results2 = await asyncio.gather(
        get_all_group_members(),
        get_user_name()
    )
    return results, results2

final_results, final_results2 = asyncio.run(main())

方案2:手动管理事件循环(不推荐)

若需分开调用,可手动创建并复用事件循环,但这种方式不够简洁,且仍可能存在客户端资源绑定问题:

# 创建并设置事件循环
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)

try:
    # 运行第一个协程
    results = loop.run_until_complete(get_all_group_members())
    # 运行第二个协程
    results2 = loop.run_until_complete(get_user_name())
finally:
    # 最后关闭循环
    loop.close()

额外优化:并行获取用户信息

原get_group_user中串行获取用户信息效率较低,可改为并行:

async def get_group_user(groupID, graphServiceClient):
    memberList = []
    members = await graphServiceClient.groups.by_group_id(groupID).members.get()
    if members and members.value:
        # 批量创建获取用户的任务
        tasks = [
            graphServiceClient.users.by_user_id(member.id).get()
            for member in members.value
        ]
        # 并行执行所有任务
        users = await asyncio.gather(*tasks)
        # 过滤有效用户并收集显示名称
        memberList = [user.display_name for user in users if user]
    return memberList

内容的提问来源于stack exchange,提问作者elahren

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 23:18:15