Исключение Python — asyncio — Task никогда не извлекалось

#python #asynchronous #python-asyncio #coroutine

#python #асинхронный #python-asyncio #сопрограмма

Вопрос:

Описание: (упрощенное)

  • У меня есть 2 задачи.
  • В каждой задаче у меня есть 3 сопрограммы.
  • сбой 2 сопрограмм из первой задачи. (имитация)
  • При обработке результатов задачи я получаю одно сообщение «Исключение задачи не было получено».
  • Я полагаю, это связано с тем, что было обработано исключение только одной из двух неудачных сопрограмм в этой задаче.
  • Как мне обработать исключения обеих сопрограмм в задаче и / или избежать сообщения «Исключение задачи не было получено»?

Код: (упрощенный)

 import asyncio
async def download(data):
    filename = "*" if data in ["b", "c"] else data  # simulated failure
    with open(filename, "w") as f:
        f.write(data)
async def coro(data_list):
    coroutines = [download(data) for data in data_list]
    for coroutine in asyncio.as_completed(coroutines):
        await coroutine
async def main():
    task1 = asyncio.create_task(coro(["a", "b", "c"]))
    task2 = asyncio.create_task(coro(["d", "e", "f"]))
    results = await asyncio.gather(task1, task2, return_exceptions=True)
    for _ in results:
        pass
asyncio.run(main())
 

Вывод: (упрощенный)

 Task exception was never retrieved
future: <Task finished coro=<download() done, defined at D:/myscript.py:2> exception=OSError(22, 'Invalid argument')>
Traceback (most recent call last):
  File "D:/myscript.py", line 4, in download
    with open(filename, "w") as f:
OSError: [Errno 22] Invalid argument: '*'
 

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

1. Можете ли вы повторить ту же проблему с общедоступными URL-адресами, чтобы мы могли попробовать и воспроизвести ее?

2. @user4815162342 — Спасибо. Да, я значительно упростил код и сделал его воспроизводимым. Также сузил проблему только до asyncio. Пожалуйста, обратитесь к отредактированному вопросу.

3. Возможно, вы зашли слишком далеко с упрощением, потому что это совершенно другая ошибка — Windows не нравится * символ в именах файлов, а изменение имени файла в любом случае не работает с Python open() .

4. Ya. Я специально добавил неправильное имя файла * , чтобы просто имитировать исключения задачи и посмотреть, как получить их все.

Ответ №1:

Если вы хотите собирать исключения вместо их создания, вы asyncio.gather(return_exceptions=True) также можете использовать coro in . Например:

 import asyncio

async def download(data):
    if data in ['b', 'c']:
        1/0    # simulate error
    return 42  # success

async def coro(data_list):
    coroutines = [download(data) for data in data_list]
    return await asyncio.gather(*coroutines, return_exceptions=True)

async def main():
    task1 = asyncio.create_task(coro(["a", "b", "c"]))
    task2 = asyncio.create_task(coro(["d", "e", "f"]))
    return await asyncio.gather(task1, task2, return_exceptions=True)

print(asyncio.run(main()))
 

Это выведет:

 [[42, ZeroDivisionError('division by zero'), ZeroDivisionError('division by zero')], [42, 42, 42]]