@KODYAcoder

Как решить проблему с заморозкой цикла на Python?

Суть вопроса в следующем - функция main постоянно проверяет базу данных на предмет изменения значений. Далее при определённом условии должна запускать функцию logic. Она её запускает, но в тот же момент идёт заморозка цикла while true. Как сделать игнорирование await и при выполнении условия не замораживать цикл, а запустить функцию и дальше проверять бд по циклу?

P.S. Функция logic обязательно должна быть async, т.к. там используется pyrogram
async def main():
        logger.info('')
        dbase.until_start_bot()
        in_process = list()
        while True:
            result = dbase.search_in_queue()
            if result is not None:
                ignoring_flag = False
                for res in in_process:
                    if res == result[1]:
                        ignoring_flag = True
    
                if not ignoring_flag:
                    in_process.append(result[1])
                    await logic(result)
                else:
                    pass

    async def logic(result):
         """Continue"""
        pass
  • Вопрос задан
  • 94 просмотра
Пригласить эксперта
Ответы на вопрос 2
Vindicar
@Vindicar
RTFM!
await приостанавливает текущую корутину, пока не выполнится корутина под await.
Если нужно запланировать вызов корутины, не дожидаясь выполнения - create_task() в помощь.
При этом значение (задача), которое вернёт create_task(), тоже можно (можно! но не обязательно) await'ить.
Как следствие, ты можешь собрать эти задачи в список, а потом дождаться их всех скопом с помощью asyncio.gather(), если тебе нужен возвращённый результат или нужно быть уверенным, что эти задачи завершились.
А если ни то, ни то не нужно, то можно оставить задачи как есть, они сами "довыполнятся" по ходу работы программы.
Ответ написан
Комментировать
shurshur
@shurshur
Сисадмин, просто сисадмин...
Надо просто понимать, что asyncio - это не многопоточность (хотя и указан этот тэг в вопросе). Это один процесс, который выполняет только одну задачу в каждый момент времени. И переключает он задачи только тогда, когда какая-то из них запускает операцию ввода-вывода или что-то ещё подобное (например, asyncio.sleep).

Например, если мы сделаем запрос к базе данных (с асинхронной библиотекой работы с этой базой обязательно! например, вместо sqlite3 используем aiosqlite), то пока база данных думает над ответом, скрипт может переключиться к какой-то другой ожидающей выполнения задаче. Когда база ответит, то цикл событий (event loop) вернёт управление задаче, которая сделала запрос к базе.

В приведённом примере кода есть два места, которые могут быть узкими:

1. Функция logic может быть и объявлена async, но если она делает чисто вычислительные операции без ввода-вывода (асинхронного), то в процессе её работы никогда не будет переключения на цикл события и, как следствие, не будут выполняться другие задачи. Даже если их собственный ввод-вывод уже совершился и задачи могут быть продолжены.

2. Сама работа с базой может также блокировать цикл событий.

Например, пусть logic работает 10 секунд, а dbase.search_in_queue - 5 секунд, и обе они содержат только синхронный код. Тогда пока выполняется dbase.search_in_queue свои 5 секунд, не будет выполняться logic, и наоборот.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы