Skip to content

MaxShoshin/GZipTest

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Gzip test

Задача

Написать консольную программу на C#, предназначенную для поблочного сжатия и расжатия файлов с помощью System.IO.Compression.GzipStream.

Для компрессии исходный файл делится на блоки одинакового размера, например, в 1 мегабайт. Каждый блок компрессится и записывается в выходной файл независимо от остальных блоков.

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

В случае исключительных ситуаций необходимо проинформировать пользователя понятным сообщением, позволяющим пользователю исправить возникшую проблему, в частности если проблемы связаны с ограничениями операционной системы. При работе с потоками допускается использовать только стандартные классы и библиотеки из .Net 3.5 (исключая ThreadPool, BackgroundWorker, TPL). Ожидается реализация с использованием Thread-ов.

Параметры программы, имена исходного и результирующего файлов должны задаваться в командной строке следующим образом:

GZipTest.exe compress/decompress [имя исходного файла] [имя результирующего файла]

Реализация

Основной алгоритм компресии/декомпрессии находится в классе Pipeline. Класс создает несколько потоков (по количеству процессоров) для трансформации (компрессия или декомпрессия) и по одному потоку на чтение и запись в stream.

Основной алгоритм

  • Читающий поток читает из исходного файла данные поблочно и складывает блоки в очередь с ограничениями для трансформации.
  • Потоки трансформации ждут когда в очереди появится блок для трансформации, выбирают его, трансформируют (сжимают или расжимают) и складывают результат в очередь (тоже с ограничением) на запись.
  • Записывающий поток вытаскивает блоки из своей очереди и записывает их в результирующий файл.

Очередь с ограничениями

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

За идею взята System.Collection.Concurrent.BlockingCollection. Реализована с помощью семафоров.

В качестве основной очереди - реализована потокобезопасная очередь без блокировок потока (Interlocked.CompareExchange). Тесты показали, что очередь с обычными lock будет работать примерно так-же (практически отсутствует lock contention), но решил не убирать эту реализацию.

Memory traffic

Для эффективной работы с памятью стараюсь не создавать много объектов, переиспользовать буфера при копировании данных из одного stream в другой. Для этого написан BufferPool, самая простая реализация (по хорошему надо использовать ArrayPool).

Для эффективной работы с потоковыми данными в памяти используется RecyclableMemoryStream (сторонний nuget пакет). Он наследник MemoryStream, внутри себя он может использовать несколько массивов для хранения данных, лишний раз не копируя их.

ToDo:

  • Chaos monkey tests
  • Sinthetic benchmarks (what if disk is slow or CPU or low memory)
  • Reference implementation via MS Pipeline API

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages