Потоки и процессы Python: двухэтапное резервное копирование

Напишите решение на Python и проверьте его на странице.

Другие упражнения по этой теме: Concurrent futures Python: задачи на ThreadPoolExecutor и ProcessPoolExecutor.

Двухэтапное резервное копирование

Модуль фонового резервного копирования обрабатывает входящие файлы в два этапа. Сначала он вычитывает сырые блоки данных из сетевого хранилища, а затем сжимает полученный массив тяжелым алгоритмом с расчетом контрольной суммы. Поскольку сетевая загрузка почти не нагружает процессор, её выполняют в пуле потоков ThreadPoolExecutor. Процедура сжатия, напротив, полностью загружает ядро вычислениями и направляется в пул процессов ProcessPoolExecutor.

Если сетевое чтение конкретного файла завершается ошибкой, задача сжатия для него вовсе не создается. В итоговом реестре такой файл помечается как пропущенный с сохранением текста возникшей сетевой ошибки.

Спроектируйте диспетчер двухэтапной обработки, который возвращает словарь с успешными контрольными суммами и зафиксированными сетевыми сбоями с сохранением исходного порядка файлов.

Что уже дано

При выполнении программы уже доступны готовые тестовые средства make_archive_probe, make_process_probe, а также функция сжатия compress_block(file_id, data). Реализовывать заново алгоритмы сетевого чтения и сжатия не требуется: они передаются аргументами в вашу функцию.

Вам необходимо написать реализацию функции archive_files.

Что нужно сделать

Реализуйте функцию archive_files(file_ids, fetch, compress, io_pool, cpu_pool).

Параметры функции:

  • file_ids — упорядоченный список, содержащий от 0 до 8 уникальных непустых ASCII-идентификаторов файлов (буквы, цифры, символ подчеркивания, длина каждого имени до 30 символов);
  • fetch — синхронная функция fetch(file_id), которая возвращает прочитанные байты bytes (длиной от 0 до 4096) либо возбуждает исключение OSError (длина сообщения от 0 до 100 символов);
  • compress — доступная для импорта функция compress(file_id, actual_fetched_bytes), возвращающая целочисленную контрольную сумму int;
  • io_pool — инициализированный пул потоков ThreadPoolExecutor;
  • cpu_pool — инициализированный пул процессов ProcessPoolExecutor.

Функция должна вернуть словарь с двумя ключами: "checksums" и "skipped".

Правила диспетчеризации:

  • Сетевое чтение каждого файла должно производиться ровно один раз через io_pool путем вызова fetch(file_id).
  • Только если сетевое чтение файла завершилось успешно, полученные байты отправляются на сжатие в cpu_pool через compress(file_id, data). Для успешно прочитанного файла сжатие запускается ровно один раз.
  • Если сетевое чтение завершилось ошибкой OSError, задача сжатия для этого файла не создается вообще. В словарь skipped записывается строковое представление ошибки str(error).
  • В словаре checksums сохраняются пары file_id: checksum для всех успешно обработанных файлов.
  • Порядок ключей в checksums и skipped должен строго соответствовать исходному относительному порядку идентификаторов в списке file_ids.
  • Если подходящих файлов для какой-либо части нет (или входной список file_ids пуст), соответствующее значение должно оставаться пустым словарем {}.

Ввод и вывод

Стандартные потоки stdin и stdout не используются: считывать ввод и вызывать print не требуется. Проверяющая система после выполнения кода ученика находит в пространстве имен функцию верхнего уровня archive_files и вызывает её напрямую.

Пример использования

probe = make_archive_probe([('file_a', [65, 65, 66]), ('file_b', [9])], {'file_b': 'storage unavailable'})
print(probe.run()['result'])

Вывод:

{'checksums': {'file_a': 399}, 'skipped': {'file_b': 'storage unavailable'}}
РешениеPython

Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.

Отправьте решение, чтобы увидеть результаты тестов.

Связанные задачи