{"id":49077559,"url":"https://github.com/s00inx/goarchiver","last_synced_at":"2026-04-20T10:34:35.155Z","repository":{"id":339814217,"uuid":"1149875114","full_name":"s00inx/goarchiver","owner":"s00inx","description":"highly-performance archiver on golang using Huffman algorithm without external libraries and focused on memory-consuming optimization","archived":false,"fork":false,"pushed_at":"2026-02-05T12:02:20.000Z","size":25,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-21T23:28:57.334Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/s00inx.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-04T16:14:00.000Z","updated_at":"2026-02-05T12:06:31.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/s00inx/goarchiver","commit_stats":null,"previous_names":["s00inx/goarchiver"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/s00inx/goarchiver","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/s00inx%2Fgoarchiver","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/s00inx%2Fgoarchiver/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/s00inx%2Fgoarchiver/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/s00inx%2Fgoarchiver/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/s00inx","download_url":"https://codeload.github.com/s00inx/goarchiver/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/s00inx%2Fgoarchiver/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32043178,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-20T10:33:29.490Z","status":"ssl_error","status_checked_at":"2026-04-20T10:32:30.107Z","response_time":94,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-20T10:34:34.409Z","updated_at":"2026-04-20T10:34:35.134Z","avatar_url":"https://github.com/s00inx.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# goarchiver\n\n**goarchiver** — архиватор на языке Go, на основе алгоритма сжатия Хаффмана. Фокус в проекте делался на максимальную оптимизацию использования памяти и эффективную работу с кэшем процессора.\n#### Ключевые особенности:\n\n-  **Нет внешних зависимостей** - используется стандартная библиотека Go.\n-  **Эффективное использование памяти** - минимальное количество аллокаций благодаря использованию `sync.Pool`.\n-  **Гарантия целостности данных** - встроенная проверка целостности данных с помощью CRC32.\n\n# Бенчмарки и производительность\nТестирование проводилось на **Intel Core Ultra 5 125H**. \n### Основные показатели скорости (1 Мб сырых данных):\nТестирование проводилось с одинаковым объемом сырых данных.\n\n```\nUnpack       8060137 ns/op     138.22 MB/s        4712 B/op         12 allocs/op\nPack         4905285 ns/op     227.12 MB/s       7146 B/op         10 allocs/op\n```\n\nБлагодаря использованию `sync.Pool` и переиспользованию буферов, нагрузка на GC минимальна, что позволяет использовать архиватор в высоконагруженных пайплайнах. Распаковка занимает гораздо больше времени из-за особенностей цикла декодирования (и это дает почву для следующей оптимизации).\n\n### Сравнение с `compress/gzip`\nСравним скорость, потребление памяти и степень сжатия, для этого будем использовать реальные данные из [**Silesia Corpus**]([Silesia corpus - Wikipedia](https://en.wikipedia.org/wiki/Silesia_corpus?ysclid=ml83q92khm133974630)). \nБыли выбраны файлы dickens (английский текст - стандартный случай), mozilla (сложные бинарные данные с высокой энтропией), nci (научные расчёты), reymont (текст на польском языке - для проверки с другой кодировкой)\n#### Сравнение скорости и потребления\n##### Сжатие (compression):\n\n|  **Файл**   | **Инструмент** | **Скорость (MB/s)** | **Память (B/op)** | **Аллокации** |\n| :---------: | :------------: | :-----------------: | :---------------: | :-----------: |\n| **reymont** | **goarchiver** |     **172.78**      |     **16 KB**     |    **10**     |\n|             |      Gzip      |        19.09        |      271 KB       |       5       |\n| **dickens** | **goarchiver** |     **178.66**      |     **20 KB**     |    **10**     |\n|             |      Gzip      |        26.76        |      271 KB       |       5       |\n| **mozilla** | **goarchiver** |     **162.77**      |     **76 KB**     |    **12**     |\n|             |      Gzip      |        39.94        |      813 KB       |      16       |\n|   **nci**   | **goarchiver** |     **200.82**      |     **47 KB**     |    **11**     |\n|             |      Gzip      |       110.47        |      203 KB       |       4       |\n##### Анализ ключевых показателей\n\n###### 1. Скорость обработки \n- **Текстовые данные:** `goarchiver` обходит Gzip в **6.5 – 9 раз**. Это достигается за счет использования энтропийного кодирования без ресурсозатратного поиска повторов строк (LZ77).\n- **Бинарные данные:** Даже на сложных данных (`mozilla`) скорость остается стабильно высокой (~160 MB/s), в то время как Gzip сильно замедляется.\n###### 2. Эффективность памят\n- **Расход RAM:** В среднем `goarchiver` потребляет в **10–15 раз меньше** оперативной памяти.\n- **Стабильность:** Потребление памяти у `goarchiver` крайне низкое и предсказуемое. Это делает его идеальным для использования в микросервисах с жесткими лимитами.\n###### 3. Нагрузка на Garbage Collector \n- Несмотря на то, что у Gzip в некоторых тестах чуть меньше аллокаций (из-за записи напрямую в `io.Discard`), общий объем выделяемой памяти у него в разы выше.\n- **10-12 аллокаций** у `goarchiver` — это результат, гарантирующий отсутствие \"фризов\" системы при обработке больших архивов.\n\n##### Распаковка (decompression):\n\n| **Данные**  | **Инструмент** | **Скорость (MB/s)** | **Память (B/op)** | **Аллокации** |\n| :---------: | :------------: | :-----------------: | :---------------: | :-----------: |\n| **reymont** | **goarchiver** |      **73.20**      |     **7 KB**      |    **12**     |\n|             |      Gzip      |        271.27       |       116 KB      |      677      |\n| **dickens** | **goarchiver** |      **65.47**      |     **9 KB**      |    **12**     |\n|             |      Gzip      |        198.76       |      309 KB       |      1865     |\n| **mozilla** | **goarchiver** |      **70.00**      |     **22 KB**     |    **14**     |\n|             |      Gzip      |        257.55       |      6723 KB      |     38951     |\n|   **nci**   | **goarchiver** |      **130.24**     |     **13 KB**     |    **13**     |\n|             |      Gzip      |        798.00       |       121 KB      |      1067     |\n\n###### 1. Скорость обработки\n- `goarchiver` держит уверенные 65–130 MB/s. На бинарных структурах без явных повторов разрыв с Gzip сокращается, так как чистый Хаффман эффективнее обрабатывает данные с высокой энтропией.\n###### 2. Эффективность памяти \n- **Расход RAM**: `goarchiver` потребляет в 15–30 раз меньше памяти на текстах и до 300 раз меньше на сложных бинарных данных (mozilla: 22 KB против 6.7 MB).\n- **Предсказуемость:** мой архиватор использует фиксированные буферы и пулы. Это исключает внезапные скачки потребления ресурсов, что критично для облачных микросервисов с жесткими квотами (LXC/Docker limits).\n###### 3. Нагрузка на Garbage Collector \n- **Минимум аллокаций:** cтабильные 12–14 аллокаций на операцию. Для сравнения: Gzip на бинарных данных создает почти 39,000 объектов, перегружая сборщик мусора.\n- **Отсутствие \"фризов\":** благодаря тому, что объем выделяемой памяти (B/op) мал, нагрузка на CPU со стороны GC практически отсутствует. \n#### Сравнение степени сжатия\n| **Файл**    | **Оригинал (КБ)** | **Gzip (КБ)** | **GoArchiver (КБ)** | **Сжатие (%)** |\n| ----------- | ----------------- | ------------- | ------------------- | -------------- |\n| **mozilla** | 50 020            | 18 603        | **39 041**          | ~22%           |\n| **nci**     | 32 768            | 3 125         | **9 985**           | ~70%           |\n| **dickens** | 9 954             | 3 778         | **5 690**           | ~43%           |\n| **reymont** | 6 472             | 1 816         | **3 938**           | ~39%           |\n\n`goarchiver` использует чистый алгоритм Хаффмана, из-за этого уступает `gzip` (который использует deflate) в степени сжатия. Но он оптимизирован для максимальной скорости при сохранении достойного уровня сжатия.\n-  **максимальное сжатие (nci):** до **70%** экономии места.\n-  **среднее сжатие текста:** **40-45%**.\n\nЗначит `goarchiver`подойдёт для **инфраструктур с дефицитом ресурсов**, где скорость упаковки и стабильность RAM важнее плотности сжатия. Он идеально подходит для микросервисов и Edge-систем, так как потребляет до **230 раз меньше памяти** и работает в **6–9 раз быстрее Gzip** на упаковке логов и бинарных данных, практически не нагружая сборщик мусора (GC).\n# Технические детали\n\nПроект спроектирован с упором на эффективное использование кэш-линий процессора и минимизацию давления на Garbage Collector (`Mechanical Sympathy`).\n### Алгоритм и оптимизации\n\nСжатие выполняется в три этапа и 2 прохода по файлу по алгоритм\n1. **Статистический анализ:** \n\t  Однопоточный сбор частот символов.\n2. **Построение модели:**\n    - **Flat Memory Layout:** Бинарная куча и дерево Хаффмана реализованы на базе **плоских массивов**. Это исключает прыжки по указателям, обеспечивая высокую локальность данных и эффективную работу L1/L2 кэша.\n    - **Zero-allocation build:** Память под дерево аллоцируется единоразово. Узлы имеют фиксированный размер, что позволяет вычислить объем памяти заранее.\n    - **Canonical Huffman:** Дерево приводится к каноническому виду. Это позволяет восстанавливать таблицу кодов, храня только их длины, что значительно уменьшает размер заголовка.\n3. **Кодирование:**\n    - **Pooling:** Для минимизации аллокаций в куче используется `sync.Pool`. Тяжелые структуры (деревья) переиспользуются между операциями.\n    - **Integrity:** CRC32 вычисляется параллельно с кодированием в том же буфере, обеспечивая контроль целостности без дополнительных проходов по памяти.\n\nРаспаковка выполняется в три этапа за один проход по сжатым данным:\n1. **Восстановление модели (Prepare Data):**\n    - На основе таблицы длин, считанной из заголовка, восстанавливается структура канонического дерева Хаффмана.\n    - Вместо построения дерева из узлов и указателей формируются четыре компактных массива-справочника (`mincodes`, `symb`, `offsets`, `counts`). Это позволяет декодировать символы, используя только арифметику массивов.\n    - Использование плоских массивов гарантирует, что все данные для поиска символа помещаются в кэш-линию процессора, исключая дорогостоящие промахи по памяти.\n2. **Декодирование (Bitstream Processing):**\n    - Реализован механизм `fillacc`, который подгружает данные в 64-битный аккумулятор. Это позволяет обрабатывать биты в памяти регистрами процессора, не обращаясь к `io.Reader` для каждого бита.\n    - Функция `decodeNext` находит символ за один проход по массиву длин. Благодаря каноническому виду, поиск осуществляется простым сравнением числового кода с минимальным значением для данной длины (`code \u003c mincodes[l] + counts[l]`).\n    - Основной цикл распаковки не создает новых объектов в куче. Вся обработка происходит в рамках заранее выделенных массивов на стеке или в пуле.\n3. **Стриминг и контроль (Streaming \u0026 Integrity):**\n    - Выходные данные накапливаются в буфере из `sync.Pool` и сбрасываются в `io.Writer` блоками по 32 КБ. Это оптимизирует системные вызовы записи.\n    - CRC32 вычисляется непосредственно в процессе записи декодированных байт.\n    - После обработки `originalSize` байт выполняется сверка контрольной суммы. Остаток бит в аккумуляторе синхронизируется, чтобы извлечь 4-байтовый хеш и подтвердить целостность данных.\n### Формат файла\n\nБинарная структура файла оптимизирована для компактности:\n\n|**Смещение**|**Размер**|**Описание**|\n|---|---|---|\n|`0-1`|2 байта|**Magic Bytes** (идентификатор формата)|\n|`2-3`|2 байта|Длина оригинального имени файла ($N$)|\n|`4-(4+N)`|$N$ байт|Оригинальное имя файла и расширение|\n|`...`|8 байт|Размер несжатых данных (uint64)|\n|`...`|1 байт|**Tree Metadata:** `0` — полная таблица (256 байт); `1-32` — разреженная таблица (пары символ-длина)|\n|`...`|Variable|Таблица длин кодов Хаффмана|\n|`...`|Variable|Сжатые данные (Payload)|\n|Конец|4 байта|Контрольная сумма **CRC32**|\n\n\u003e Адаптивное хранение дерева (полное или разреженное) позволяет существенно экономить место на файлах с малым алфавитом.\n\u003e \n# Быстрый старт\n\n### Готовый исходник\n\nВы можете скачать уже скомпилированный .exe файл из Releases, который не потребует установки ничего больше (чтобы пользоваться надо добавить в PATH).\n### Установка и сборка\n\nПеред установкой убедитесь, что у вас установлен Go версии 1.23 или новее и утилита make на Windows ([Make for Windows](https://gnuwin32.sourceforge.net/packages/make.htm)).\nВы можете сами скомпилировать исполняемый файл. и чтобы пользоваться архиватором из любой точки компьютера вам надо будет вручную добавить путь к exe в PATH.\n\n```bash\ngit clone https://github.com/kfcemployee/goarchiver.git\ncd goarchiver\nmake build\n```\n\nИли можно скомпилировать и добавить в PATH одной командой. \n```bash\ngit clone https://github.com/kfcemployee/goarchiver.git\ncd goarchiver\nmake install\n```\n(никаких внешних зависимостей и go.sum не нужно)\n\n... если у вас вдруг возникли проблемы с make:\n```bash\ngit clone https://github.com/kfcemployee/goarchiver.git\ncd goarchiver\ngo build -ldflags=\"-s -w\" -o goarc.exe ./cmd/goarc/main.go\n```\n### Использование\n\n```\n# Сжатие\ngoarc p \u003cfile\u003e\n\n# Распаковка\ngoarc u \u003cfile.arc\u003e\n```\n### Запуск тестов и бенчмарков\n\n```bash\nmake test # тесты\nmake bench # бенчмарки\nmake benchcpu # бенчмарк на разном количестве ядер\n```\n## Структура проекта\n\n- `/cmd/goarc` — CLI интерфейс.\n- `/internal/engine` — Ядро архиватора (логика сжатия и LUT).\n- `Makefile` — Скрипты сборки и тестирования.\n## Лицензия.\n\nThis project is licensed under the MIT License - see the [LICENSE](https://www.google.com/search?q=LICENSE) file for details.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fs00inx%2Fgoarchiver","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fs00inx%2Fgoarchiver","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fs00inx%2Fgoarchiver/lists"}