Asyncio Queue: обработка ошибок воркеров и подтверждение taskdone
Напишите решение на Python и проверьте его на странице.
Другие упражнения по этой теме: Asyncio Queue, Lock и Semaphore: задачи на очереди и воркеров.
Конвейер досмотра багажа
Автоматизированный пункт досмотра направляет багаж через очередь в сканер, где одновременно может проверяться не более заданного числа мест. Несколько воркеров-инспекторов забирают чемоданы из очереди и выполняют асинхронную проверку, при этом любое место багажа способно вызвать аварийный сигнал сканера.
Если проверка проходит успешно, вес чемодана добавляется в общую сводку пропущенного груза, защищённую замком от одновременных правок. При аварии багаж направляется в отдельный список ручного досмотра с сохранением типа возникшего сбоя. Каким бы ни был исход — штатным пропуском или сбоем, — чемодан обязательно снимается с учёта очереди, чтобы ожидание завершения смены не зависло.
Реализуйте функцию конвейера досмотра, которая распределяет багаж между воркерами, ограничивает число одновременных сканирований с помощью семафора, изолирует обновление весовых данных через замок и возвращает суммарный вес пропущенного груза вместе с реестром аварийных чемоданов.
Что уже дано
В редакторе представлена заготовка асинхронной функции screen_baggage(station, scanner, worker_count), которую необходимо реализовать.
Объект пункта досмотра station создаётся фабрикой make_baggage_station(bags, max_scans) и предоставляет следующие атрибуты и методы:
station.queue— очередьasyncio.Queue, в которую уже помещены все кортежи багажа (новые элементы извне не поступают);station.slots— семафорasyncio.Semaphore, ограничивающий одновременные проверки числом слотов сканераmax_scans(от 1 до 16);station.lock— замокasyncio.Lockдля синхронизации записи в весовую сводку;station.total— целочисленный счётчик суммарного веса (изначально0);station.failures— список для фиксации сбоев проверки (изначально пустой);station.start_workers(worker_factory, worker_count, *, task_group=None)— готовый вспомогательный метод создания пула воркеров. Он принимает фабрикуworker_factory(вызываемый объект без аргументов, возвращающий новую корутину одного воркера), создаёт ровноworker_countзадачasyncio.Taskи возвращает их список. Если передан параметрtask_group, задачи создаются черезtask_group.create_task, иначе черезasyncio.create_task.
Что нужно сделать
Реализуйте асинхронную функцию screen_baggage(station, scanner, worker_count) -> tuple[int, list[tuple[tuple[str, int], str]]].
Параметры функции:
station— объект пункта досмотраBaggageStation;scanner— асинхронная функцияscanner(bag), выполняющая досмотр конкретного места багажа;worker_count— целое число воркеров в пуле (от 1 до 16).
Каждое место багажа представлено кортежем bag = (label, weight), где label — строка метки багажа длиной от 1 до 64 символов (метки могут повторяться), а weight — неотрицательный целый вес от 0 до 1 000 000. Общее количество чемоданов — от 0 до 200.
Правила работы конвейера:
- Сформируйте фиксированный пул воркеров однократным вызовом метода
station.start_workers(worker_factory, worker_count, ...). Непосредственное извлечение чемоданов из очереди и вызовы сканера должны производиться именно внутри задач этого зарегистрированного пула. - Каждый воркер обрабатывает по одному чемодану за раз, забирая его из
station.queue. - Вызов
await scanner(bag)для каждого чемодана выполняется строго при удерживаемом разрешении семафораstation.slots. - Если
scanner(bag)завершился штатно, вес чемоданаbag[1]прибавляется кstation.total. Каждое обновлениеstation.totalобязано происходить строго под защитой замкаstation.lock. - Если
scanner(bag)выбросил обычное исключение (Exception), этот чемодан считается аварийным. Исключение должно быть перехвачено: в списокstation.failuresдобавляется кортеж(bag, type(error).__name__). Сбой не должен останавливать обработку остальных чемоданов очереди. - Для каждого извлечённого из очереди чемодана метод
station.queue.task_done()вызывается ровно один раз и строго после завершения его досмотра (как успешного, так и аварийного). Раннее подтверждение до завершения проверки запрещено. - После обработки всех чемоданов из очереди все воркеры должны быть корректно остановлены и ожидаемы через
await, а все удерживаемые разрешения семафора и замка — освобождены. - Функция должна вернуть кортеж
(station.total, failure_list). Вfailure_listдолжны войти все возникшие сбои (включая повторяющиеся места багажа); порядок записей в списке сбоев не регламентируется.
Ввод и вывод
Стандартные потоки ввода stdin и вывода stdout в решении не используются: считывать ввод и вызывать print() не нужно. После выполнения кода учащегося проверяющая система считывает из пространства имён модуля функцию верхнего уровня screen_baggage и ожидает её вызов с подготовленными проверочными объектами станции и сканера.
Пример использования
async def example():
station = make_baggage_station([("A", 4), ("B", 9), ("C", 3)], 2)
async def scanner(bag):
await asyncio.sleep(0)
if bag[0] == "B":
raise ValueError("scan")
total, failures = await screen_baggage(station, scanner, 2)
print(total)
print(sorted((bag[0], name) for bag, name in failures))
asyncio.run(example())
Вывод:
7
[('B', 'ValueError')]
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Связанные задачи
- Race condition в asyncio: почему однопоточность не защищает счётчик
- Asyncio Queue и Semaphore: конвейер с ограничением нагрузки
- Asyncio Queue: вытеснение старейшей заявки без блокировки поставщика
- Asyncio Lock и Semaphore: учёт результатов обработки контейнеров
- Asyncio: восстановление пула воркеров после ошибки
- Asyncio Queue: объединение парных событий по идентификатору
