Asyncio timeout: остановка по таймауту и внешней отмене
Напишите решение на Python и проверьте его на странице.
Другие упражнения по этой теме: Отмена и таймауты asyncio: задачи на cancel, shield и graceful shutdown.
Ступенчатое погружение
Глубоководный аппарат погружается ступенчато, задерживаясь на каждой отметке маршрута для выравнивания внутреннего давления перед переходом глубже. На каждом таком шаге стабилизация ограничена защитным интервалом asyncio.timeout. Если автоматика успевает стравливать давление вовремя, батискаф благополучно переходит к следующей глубине.
Если же защитный интервал истекает раньше, чем стабилизируется давление, регулятор обязан немедленно остановить погружение, сбросить балласт и зафиксировать предельную безопасно достигнутую глубину. Параллельно система следит за сигналами управления: команда аварийного всплытия от капитана отменяет текущую стабилизацию, и регулятор возвращает статус ручной эвакуации, строго отделяя внешнее вмешательство от автоматического срабатывания локального таймаута.
Определите предельную глубину погружения и итоговый статус остановки для штатного маршрута, превышения лимита времени на выравнивание давления и ручной отмены операции.
Что уже дано
В среде исполнения уже доступны вспомогательные функции observe_depth_probe и make_depth_example_observation для проверки поведения регулятора в стандартном цикле событий. Вам необходимо реализовать корутину descend_route.
Что нужно сделать
Реализуйте асинхронную функцию descend_route(depths, stabilize, drop_ballast, step_timeout).
Функция принимает четыре параметра:
depths— список строго возрастающих неотрицательных чисел (от 0 до 20 отметок, значения от 0 до 1 000 000);stabilize— предоставленная корутинаstabilize(depth), которая либо успешно завершается с произвольным результатом (включая ложные значения, такие какNone,Falseили0), либо остаётся в ожидании до наступления таймаута или отмены;drop_ballast— синхронная функция сброса балласта без аргументов;step_timeout— положительное число секунд (от 0.001 до 1.0) для ограничения времени стабилизации на каждой отдельной отметке.
Функция должна вернуть словарь ровно с двумя ключами:
safe_depth— последняя отметка маршрута, на которой стабилизация завершилась успешно, либоNone, если ни одна отметка не была успешно пройдена;status— строковый статус завершения:'complete','timeout'или'manual'.
Правила выполнения погружения:
- Отметки из
depthsобрабатываются строго по порядку. Переход к следующей глубине возможен только после успешного завершенияstabilize(depth)на текущей отметке. - Стабилизация на каждом шаге выполняется внутри собственного интервала нативного контекстного менеджера
asyncio.timeout(step_timeout). - Если на текущем шаге истекает локальный лимит времени
step_timeout, батискаф прекращает движение дальше, вызывает синхронную функциюdrop_ballast()и возвращает результат со статусом'timeout'и последней зафиксированной отметкойsafe_depth. - Если текущая задача прерывается внешней отменой (координатор вызывает отмену задачи), выполнение стабилизации прерывается, функция возвращает словарь со статусом
'manual'и последней успешной отметкойsafe_depth. Сбрасывать балласт при ручной отмене не требуется. - Если все отметки из
depthsуспешно пройдены (или передан пустой список), функция возвращает статус'complete'. - Любые значения, возвращаемые
stabilize(depth)(в том числеFalse,0,None), считаются подтверждением успешной стабилизации. - К моменту возврата из
descend_routeне должно оставаться незавершённых фоновых задач, порождённых текущим шагом.
Ввод и вывод
Стандартные потоки ввода stdin и вывода stdout в решении не используются: считывать ввод и вызывать print() не нужно. После выполнения кода учащегося проверяющая система считывает из пространства имён модуля функцию верхнего уровня descend_route и вызывает её с проверочными аргументами.
В приведённом примере проверяется маршрут по отметкам 10 и 20 с лимитом шага 0.02 секунды. Первая отметка 10 стабилизируется мгновенно (значение False подтверждает успех), поэтому безопасная глубина фиксируется на 10. На отметке 20 стабилизация уходит в бесконечное ожидание и не укладывается в отдельный лимит времени: батискаф останавливается по таймауту, вызывает сброс балласта, а итоговая глубина остаётся равной 10 без вмешательства ручной отмены.
Пример использования
import asyncio
async def stabilize(depth):
if depth == 10:
return False
await asyncio.Event().wait()
ballast_events = []
def drop_ballast():
ballast_events.append('ballast')
report = asyncio.run(descend_route([10, 20], stabilize, drop_ballast, 0.02))
print(report['status'], report['safe_depth'])
print(ballast_events)
Вывод:
timeout 10
['ballast']
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Связанные задачи
- Asyncio CancelledError: почему except Exception не ловит отмену
- Asyncio: проверка реакции задачи на cancel() с таймаутом
- Graceful shutdown Python: завершение текущей работы перед остановкой воркера
- Asyncio shield: сохранение начатой работы при повторной отмене
- Удаление ключа из ChainMap в Python: проверка поведения del
- Обратный индекс на Python: группировка уникальных значений через defaultdict
