Pull to refresh

Comments 10

сообщения от пользователей обрабатываются параллельно.

Каким образом? насколько я помню, для этого либо мультипроцессинг нужен, либо выпилить GIL. Асинхронность же — это совсем не параллельно.

Когда выполняется io операция можно принять сообщение от другого пользователя и обработать его. А так как в боте много работы с API, то получается значительный прирост в скорости

Да это я все понимаю. Но термин «параллельно» имеет вполне устоявшееся применение и не очень-то сюда подходит. То, о чем вы говорите — это скорее неблокируемый ввод-вывод — мол, пока ждем долгой io операции, можем заняться чем-то еще.

Правильный термин в данном случае - конкурентность (concurrency), а не параллелизм. Т.е. можно сказать, что сообщения будут обрабатываться асинхронно, или что они будут обрабатываться конкурентно, но точно не параллельно, т.к. GIL пока никто не отменял.

Зачем изобретать велосипед, когда есть прекрасный aiogram

UFO just landed and posted this here

Круто увидеть у кого то похожее решение какой то проблемы) Такую же параллельную обработку очереди делал на java. В моем случае использовалась библиотека https://github.com/rubenlagus/TelegramBots и она тоже все сообщения от всех пользователей обрабатывает последовательно.

Есть один тонкий момент в обработке одной очереди: вы можете обработать два запроса от одного пользователя одновременно или не в порядке их получения, что приводит к нарушению бизнес логики. Например пользователь нажимает по очереди разные inline button, пока бот "подвис".

Как я понял, ваш пример этому подвержен. В моем проекте, на каждый "worker" создавалась дополнительная очередь. При появлении задачи в общей очереди, задача на основании TelegramID, закрепляется за свободной очередью "worker`a" и с этого времени этот "worker" обрабатывает только задачи этого TelegramID в порядке их появления. "worker" освобождается, когда его очередь кончается.
Так мне удалось решить эту проблему в моем случае.

В моем проекте, на каждый "worker" создавалась дополнительная очередь. При появлении задачи в общей очереди, задача на основании TelegramID, закрепляется за свободной очередью "worker`a" и с этого времени этот "worker" обрабатывает только задачи этого TelegramID в порядке их появления. "worker" освобождается, когда его очередь кончается.

Я правильно понимаю, старт бота запускает, например, 10 "worker"-ов, затем один из них берет задачу из общей очереди, обрабатывает задачу, после этого его очередь становится пустой и "worker"-ов становится 9.

Или же на каждого пользователя создается один "worker" с бесконечным ожиданием? И, если пользователь ушел, не закончив диалог, а вернулся часов через 12, все это время "worker" ждал когда же ему ответят? Или "worker" брал себе задачи от другого пользователя?

Может быть стоит сделать "worker"-у еще и список пользователей, задачи которых он ожидает, и, если он сейчас свободен, а другие "worker"-ы заняты, и есть задачи от нового пользователя, то он берет этого пользователя в свой список и выполняет его задачи.

Да, при старте запускается 10 worker`ов. Сообщение пользователя помещается в общую очередь. Тут уточню, что в моем случае, используемая библиотека, реализует паттерн "производитель потребитель", т.е. один поток наполняет общую очередь, другой берет из очереди задачи и решает их. Так вот, я получал от второго потока, "потребителя", задачу и передавал на выполнение в один из worker`ов.

Для наглядности даю ссылку на свой код github

Вы как раз говорите, о способе выбора worker`а для передачи ему задачи. У меня каждый worker (BotMessageQueueExecutor в моем примере) - это очередь с одним обработчиком и переменная для хранения TelegramID.

Есть класс, который получает от потока "потребителя" задачу и выбирает worker, это BotMessageExecutor. Вот в нем есть метод getAvailableExecutor() который и делает выбор worker`а. Только вот пока готовил ответ, понял, что в моем коде ошибка - спасибо вам, так бы и не заметил. Для выбора, нужно сначала найти среди worker`ов того, кто в данный момент обрабатывает задачи текущего TelegramID, если такого нет, то нужно уже искать первый свободный или простаивающий worker, даже если TelegramID не совпадают. В моем примере ошибка в этом методе, т.к. нужно сначала проверять именно все worker`ы на соответствие TelegramID, а я этого не сделал.

Таким образом, worker закрепляется за каким то TelegramID при получении задачи, но когда он будет простаивать и нам нужен будет worker для задачи с другим TelegramID, то мы можем его использовать.

Надеюсь удалось донести до вас свою мысль)

Sign up to leave a comment.