Как использовать Asyncio для запуска двух разных асинхронных функций

Я пишу сценарий, который использует API Graph для Microsoft для подключения и запроса пользовательских данных из Entra ID в Azure. У меня есть две разные функции, которые я пытаюсь использовать: одна, которая получает пользователей из указанной группы, и другая, которая извлекает отображаемое имя пользователя по значению его идентификатора. Если я использую 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)

Если я закомментирую все для второй функции, get_group_user, первая функция будет работать нормально. Если я закомментирую все для первой функции, get_all_group_members, вторая функция будет работать нормально. Просто когда я действительно запускаю оба, второй выходит из строя, и я не знаю, почему, поэтому не могу понять, как это исправить.

Почему я не могу вызвать asyncio.run() в сценарии более одного раза? Как мне изменить свой сценарий, чтобы я мог успешно запускать обе эти функции асинхронно и получать нужные мне данные?

Пожалуйста, всегда публикуйте сообщение об ошибке. Я не могу воспроизвести «что-то не работает». Как правило, asyncio.run(...) можно запустить дважды, если он выполняется последовательно, а не вложенно. Если вы столкнулись с чем-то вроде cannot create event loop if there is already an event loop running, вы, вероятно, выполнили одно asyncio.run(...) внутри другого. Это не работает.

lord_haffi 25.06.2024 00:25

честно говоря, я думаю, что все уроки показывают, что вам нужно объединить все функции в одну функцию и запускать ее с помощью одной run(). И я думаю, что run() был создан для запуска программы от начала до конца - без выхода и запуска другой run()

furas 25.06.2024 01:45

Если вы разобрались сами, то можете сами ответить на свой вопрос и отметить его как принятый! Таким образом, вопрос не остается открытым.

jupiterbjy 25.06.2024 02:47

@jupiterbjy Я не смог ответить на свой вопрос, когда сам нашел решение, но вижу, что теперь я могу добавить ответ, так что сделаю это.

elahren 25.06.2024 23:30
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
4
50
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

В документации asyncio.run указано, что его следует вызывать один раз для программы.

Эту функцию следует использовать в качестве основной точки входа для асинхронных программ, и в идеале ее следует вызывать только один раз.


Чтобы запускать что-то одновременно, вам нужно создать Task для каждой асинхронной функции. Это будет чередовать выполнение двух методов.

async def main():
    await asyncio.gather(get_all_group_members(), get_user_name())


if __name__ == '__main__':
    asyncio.run(main())

Но если одна асинхронная функция должна завершиться раньше любой другой, то ваше самостоятельно найденное решение правильное: запускает их последовательно.

await method_1()
await method_2()
...
Ответ принят как подходящий

Вот решение, которое в конечном итоге сработало после того, как я прошел через больше проб и ошибок со своей проблемой.

Чтобы иметь возможность запускать обе асинхронные функции, я создал еще одну асинхронную функцию, в которую поместил обе другие функции, а затем вызвал эту функцию с помощью 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
        
async def get_user_name():
        member = '<id value>'
        results = await gq.get_user_by_id(member=member,graphServiceClient=graphServiceClient)
        return results
        
async def run_async_functions():
        groupResults = await get_all_group_members()
        usernameResults = await get_user_name()
        return groupResults, usernameResults
            
groupResults, usernameResults = asyncio.run(run_async_functions())

После загрузки результатов обеих функций в groupResults и usernameResults я могу распечатать значения, а это значит, что я смогу взаимодействовать с ними так, как мне нужно для продвижения вперед.

Другие вопросы по теме