Почему в асинхронной функции при задержке не переключается на другую работу?

Рейтинг: 0Ответов: 1Опубликовано: 04.08.2023

Тестирую асинхронный ping. По умолчанию host3 отбрасываю в исключения, а host6 недоступный. По логике при проверке недоступного host3 во время ожидания должны сразу переключиться на проверку других хостов, но всё равно происходит ожидание. Почему так?

example

import aioping
import asyncio
from socket import gaierror


async def do_ping(host):
    try:
        await aioping.ping(host, timeout=1)
        print("UP", host)
    except TimeoutError:
        print("DOWN:", host)
    except gaierror:
        print("EXCEPTION:", host)


async def main():
    hosts = ['host1', 'host2', 'host3', 'host4', 'host5', 'host6']
    for serv in hosts:
        task = asyncio.create_task(do_ping(serv))
        await task


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

Ответы

▲ 3Принят

Вы в цикле создаете таск, и тут же ждете его завершения, до окончания ожидания код в этой функции не продолжает работать (код буквально ждет на await, пока таск не завершится, другие таски не создаются).

Вместо этого нужно сформировать список тасков и ожидать их завершения параллельно через asyncio.wait. В примере ping заменил на ожидание со случайной длительностью.

import asyncio
import random


async def do_ping(host):
    timeout = 1.0
    time = random.random() * 1.5
    if time <= timeout:
        await asyncio.sleep(time)
        if random.random() < 0.2:
            print("EXCEPTION:", host)
        else:
            print("UP", host)
    else:
        await asyncio.sleep(timeout)
        print("DOWN", host)


async def main():
    hosts = ['host1', 'host2', 'host3', 'host4', 'host5', 'host6']
    await asyncio.wait([asyncio.create_task(do_ping(serv)) for serv in hosts])


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

Пример вывода:

UP host4
UP host1
EXCEPTION: host2
DOWN host3
DOWN host5
DOWN host6