Почему это исключение сразу возникает из задачи asyncio? - PullRequest
0 голосов
/ 27 апреля 2018

Насколько я понимаю из документации, asyncio.Tasks, как подкласс asyncio.Future, будет хранить возникающие в них исключения, и их можно получить на досуге.

Однако в этом примере кода исключение возникает немедленно:

import asyncio

async def bad_task():
    raise Exception()

async def test():
    loop = asyncio.get_event_loop()
    task = loop.create_task(bad_task())
    await task

    # I would expect to get here
    exp = task.exception()
    # but we never do because the function exits on line 3

loop = asyncio.get_event_loop()
loop.run_until_complete(test())
loop.close()

Пример вывода (Python 3.6.5):

python3 ./test.py
Traceback (most recent call last):
  File "./test.py", line 15, in <module>
    loop.run_until_complete(test())
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/asyncio/base_events.py", line 468, in run_until_complete
    return future.result()
  File "./test.py", line 9, in test
    await task
  File "./test.py", line 4, in bad_task
    raise Exception()
Exception

Это особенность создания и вызова задач, когда они уже находятся внутри асинхронного кода?

Ответы [ 2 ]

0 голосов
/ 29 апреля 2018

Как объяснил Матти, исключения, вызванные сопрограммой, распространяются на ожидающий сайт. Это сделано намеренно, поскольку по умолчанию ошибки не передаются по умолчанию. Однако, если это необходимо, определенно можно дождаться завершения задачи, не обращаясь сразу к ее результату / исключению.

Вот простой и эффективный способ сделать это, используя небольшое промежуточное звено Future:

async def test():
    loop = asyncio.get_event_loop()
    task = loop.create_task(bad_task())
    task_done = loop.create_future()  # you could also use asyncio.Event
    # Arrange for task_done to complete once task completes.
    task.add_done_callback(task_done.set_result)

    # Wait for the task to complete. Since we're not obtaining its
    # result, this won't raise no matter what bad_task() does...
    await task_done
    # ...and this will work as expected.
    exp = task.exception()
0 голосов
/ 27 апреля 2018

await вызовет любое исключение, сгенерированное задачей, потому что это должно заставить асинхронный код выглядеть почти точно как синхронный код. Если вы хотите их поймать, вы можете использовать обычное предложение try...except.

...