Как запустить две задачи с помощью asyncio
Есть функция которая читает сообщения в чате, и которая принимает параметр с айди чата:
import somelib
client = somelib.Client()
client.login(email="email", password="password")
subclient = somelib.SubClient(comId="comId", profile=client.profile)
botname = subclient.get_user_info(userId=client.userId).nickname
old = []
class Bot:
async def run(self, chatid):
while True:
msg = subclient.get_chat_messages(chatId=chatid, size=2)
for message, author, messageId in zip(msg.content, msg.author.nickname, msg.messageId):
if messageId in old:
pass
else:
print(f"{author} : {message}")
if author != botname:
if message[0] == "!":
if message.lower() == "!ping":
subclient.send_message(chatId=chatid, message="Pong!")
old.append(messageId)
В файле main.py я попробовал запустить 2 задачи, которые читали бы 2 разных чата асинхронно
import asyncio
from lib.bot import Bot
bot = Bot()
async def main():
if __name__ == '__main__':
print("START")
task1 = asyncio.create_task(bot.run('881beb78-2a54-0391-2cee-94c8dfc0ce3d'))
task2 = asyncio.create_task(bot.run('a5dd10aa-551d-41b9-95f6-96fd3bf087dc'))
await task1
await task2
asyncio.run(main())
Но бот читает сообщения только с первого чата (task1), второй он игнорирует. Как сделать что бы две задачи работали одновременно ? Или как можно заставить бота читать два чата одновременно?
Ответы (2 шт):
Судя по документации, вы можете использовать asyncio.gather():
async def main():
if __name__ == '__main__':
print("START")
await asyncio.gather(bot.run('881beb78-2a54-0391-2cee-94c8dfc0ce3d'),
bot.run('a5dd10aa-551d-41b9-95f6-96fd3bf087dc'),)
asyncio.run(main())
В функции main все сделано правильно. Корутины действительно должны выполняться параллельно.
Но в корутинах нет ни одного await. Именно в этих точках управление отдается циклу событий (event-loop) и он решает, какую корутину выполнить сейчас, так происходит переключение между выполнением разных корутин. Но функция блокирует event-loop и сначала выполняется полностью первый вызов, затем второй. Но первый вызов - бесконечный цикл. До второго вызова дело никогда не дойдет.
Как тут быть? У меня вопросы к функциям get_chat_messages и send_message, судя по их названию - блокирующие. Поэтому должны быть асинхронные и вызваны с await, т.е. some_lib должна быть с поддержкой асинхронности.
Как обстоит дело:
- вызвали
get_chat_messages - получили список сообщений
- обработали его, откинув уже обработанные
- снова
get_chat_messagesи до бесконечности...
Второй чат не у дел, переключиться на него негде.
Если переписать код клиентов, добавив туда поддержку асинхронности (или использовать другой), и добавить await здесь
msg = await subclient.get_chat_messages(chatId=chatid, size=2)
и здесь
await subclient.send_message(chatId=chatid, message="Pong!")
То все должно сработать. Пока один чат получает список сообщений или занят отправкой сообщения, второй может провести свою работу и вернуть управление назад, когда сам начнет получать список сообщений или отправлять сообщение.