import asyncio
async def my_coroutine():
await asyncio.sleep(5)
return "Задача выполнена!"
async def main():
try:
result = await asyncio.wait_for(my_coroutine(), timeout=2)
print(result)
except asyncio.TimeoutError:
print("Время ожидания истекло!")
asyncio.run(main())
В этом примере, если `my_coroutine()` не завершится за 2 секунды, будет поймано исключение `asyncio.TimeoutError`.
Для обработки таймаутов в асинхронных задачах с помощью asyncio.wait_for()
, необходимо обернуть вызов корутины, которая может выполняться длительное время, в функцию asyncio.wait_for()
, указав желаемый таймаут в секундах.
Если корутина завершится до истечения таймаута, asyncio.wait_for()
вернет результат ее выполнения. Если же таймаут истечет, будет выброшено исключение asyncio.TimeoutError
. Это исключение необходимо перехватывать и обрабатывать.
Пример:
import asyncio
async def long_running_task():
"""Эмулирует задачу, которая может занять много времени."""
try:
await asyncio.sleep(5) # Имитируем долгую работу
return "Задача успешно завершена!"
except asyncio.CancelledError:
return "Задача отменена"
async def main():
try:
result = await asyncio.wait_for(long_running_task(), timeout=2) # Устанавливаем таймаут в 2 секунды
print(f"Результат: {result}")
except asyncio.TimeoutError:
print("Время ожидания истекло!")
# Здесь можно выполнить действия, если задача не успела завершиться вовремя,
# например, отменить задачу, попытаться ее перезапустить, или сообщить об ошибке.
# Важно отметить, что если задача *не отменена* при таймауте, она *продолжит выполняться в фоне*.
except asyncio.CancelledError:
print("Задача была отменена внешне")
if __name__ == "__main__":
asyncio.run(main())
В этом примере:
long_running_task()
– это корутина, представляющая собой долго выполняемую задачу. В данном случае, она просто ждет 5 секунд.asyncio.wait_for(long_running_task(), timeout=2)
– запускает long_running_task()
и устанавливает таймаут в 2 секунды.try...except
обрабатывает возможное исключение asyncio.TimeoutError
, которое будет выброшено, если long_running_task()
не завершится в течение 2 секунд.except asyncio.CancelledError
. Если задача отменена вручную (например, вызвав task.cancel()
), то будет выброшено это исключение, а не TimeoutError
.Важно: После таймаута, корутина long_running_task()
, если она не обрабатывает исключение asyncio.CancelledError
или иные, продолжит выполняться в фоновом режиме. Если необходимо прервать ее выполнение, нужно получить объект Task
, представляющий запущенную корутину, и вызвать метод task.cancel()
. Это вызовет исключение asyncio.CancelledError
внутри корутины, которое нужно корректно обработать, чтобы избежать непредсказуемого поведения.
Пример отмены задачи после таймаута:
import asyncio
async def long_running_task():
try:
await asyncio.sleep(5)
return "Задача успешно завершена!"
except asyncio.CancelledError:
print("Задача отменена внутри long_running_task")
return "Задача отменена"
async def main():
task = asyncio.create_task(long_running_task()) # Создаем объект Task
try:
result = await asyncio.wait_for(task, timeout=2)
print(f"Результат: {result}")
except asyncio.TimeoutError:
print("Время ожидания истекло! Отменяем задачу...")
task.cancel() # Отменяем задачу
try:
await task # Ждем завершения отмены задачи
except asyncio.CancelledError:
print("Задача успешно отменена")
except asyncio.CancelledError:
print("Задача была отменена внешне")
if __name__ == "__main__":
asyncio.run(main())
В этом улучшенном примере:
asyncio.create_task()
создает объект Task
, позволяющий контролировать запущенную корутину.task.cancel()
для отмены выполнения корутины.await task
в блоке except asyncio.TimeoutError
ожидает фактического завершения отмены задачи. Без этого, задача может продолжать работать в фоне, даже после того, как код обработки таймаута завершится. await task
необходимо поместить внутрь еще одного try...except
блока, так как await на отмененной задаче, вызовет исключение asyncio.CancelledError