Базовый asyncio не выполняет вторую задачу

#python #python-asyncio

Вопрос:

В этом минимальном примере я ожидаю, что программа будет печатать foo и fuu по мере выполнения задач.

 import asyncio


async def coroutine():
        
    while True:
        print("foo")

async def main():

    asyncio.create_task(coroutine())
    #asyncio.run_coroutine_threadsafe(coroutine(),asyncio.get_running_loop())
    
    while True:
        print("fuu")

asyncio.run(main())
 

Программа будет только писать fuu .
Моя цель состоит в том, чтобы просто две задачи выполнялись одновременно, но, похоже, созданная задача никогда не планируется.

Я также безуспешно пытался использовать run_coroutine_threadsafe .

Если я добавлю await asyncio.sleep(1) к основному. Созданная задача требует выполнения, и программа будет только писать foo .

Что я должен сделать, чтобы выполнить две задачи одновременно с помощью asyncio ?

Комментарии:

1. Asyncio основан на совместной многозадачности, и coroutine ни main один из них не сотрудничает. Чтобы переключать задачи, вам нужно await выражение, которое ожидает чего-то, что приостанавливается в цикле событий. В игрушечных примерах это может быть что-то вроде await asyncio.sleep(0.01) ; в реальном коде это что-то вроде line = await stream.readline() , await websocket.send(msg) , или todo = await queue.get() .

Ответ №1:

Мне нравится этот вопрос, и объяснение этого вопроса рассказывает, как работают asyncio и python.

Спойлеры — Он работает аналогично однопоточной среде выполнения Javascript.

Итак, давайте посмотрим на ваш код. У вас работает только один основной поток, который будет работать непрерывно, так как планировщику python не нужно переключаться между потоками. Теперь дело в том, что ваш основной поток, создающий задачу, фактически создает сопрограмму(зеленые потоки, управляемые планировщиком python, а не планировщиком ОС), для выполнения которой требуется основной поток.

Теперь основной поток никогда не бывает свободным, так как вы поставили значение while True, он никогда не может свободно выполнять что-либо еще, и ваша задача никогда не выполняется, потому что планировщик python никогда не переключается, потому что он занят выполнением истинного кода.

В тот момент, когда вы переводите в спящий режим, он обнаруживает, что текущая задача находится в спящем режиме, и выполняет переключение контекста, и включается ваша сопрограмма.

Мое предложение. если ваши задачи тяжелы для ввода-вывода, используйте задачи/сопрограммы, и если они тяжелы для процессора, что в вашем случае ( while True ), создайте потоки или процессы Python, а затем планировщик ОС позаботится о выполнении ваших задач, они получат фрагмент процессора для запуска while True .