TGViewer
Go for Devs Go for Devs @go_for_devs · 854 subscribers
Post #75 1.17K
💥 Как memory maps (mmap) обеспечивают в 25 раз более быстрый доступ к файлам в Go

Одно из самых медленных действий, которое можно совершить в приложении, — это системный вызов. Они медленные, потому что требуют перехода в ядро, а это дорогостоящая операция. Что делать, если нужно выполнять много операций ввода-вывода с диском, но при этом важна производительность? Один из вариантов — использовать memory maps.

Memory maps — это современный механизм Unix, позволяющий «включить» файл в виртуальную память. В контексте Unix «современный» означает появившийся где-то в 1980-х или позже. У вас есть файл с данными, вы вызываете mmap, и получаете указатель на участок памяти, где эти данные находятся. Теперь, вместо того чтобы делать seek и read, вы просто читаете по этому указателю, регулируя смещение, чтобы попасть в нужное место.

Производительность

Ниже сравнение производительности при чтении файла через memory map и через ReaderAt. ReaderAt использует системный вызов pread(), совмещающий seek и read, а mmap просто читает напрямую из памяти.


Случайное чтение (ReaderAt): 416.4 ns/op
Случайное чтение (mmap): 3.3 ns/op
---
Итерация (ReaderAt): 333.3 ns/op
Итерация (mmap): 1.3 ns/op


Почти как магия. Возможно кто-то из вас помнит Varnish Cache – ускоритель HTTP, разработанный для динамических веб-сайтов с большим количеством контента. В 2006 году именно эта возможность делала его настолько быстрым при выдаче контента. Varnish Cache использовал memory maps, чтобы доставлять данные с невероятной скоростью.

Кроме того, поскольку можно работать с указателями на память, выделенную memory map, снижается нагрузка на память и уменьшается общая задержка.

Обратная сторона memory maps

Недостаток memory maps в том, что по сути в них нельзя писать. Причина кроется в устройстве виртуальной памяти.
Когда вы пытаетесь записать в область виртуальной памяти, которая не отображена на физическую, процессор вызывает page fault. Современный CPU отслеживает, какие страницы виртуальной памяти соответствуют каким физическим страницам. Если вы пишете в страницу, которая не сопоставлена, процессору нужна помощь.

При page fault операционная система:

1. Выделяет новую страницу памяти.
2. Считывает содержимое файла по нужному смещению.
3. Записывает это содержимое в новую страницу.
4. Затем управление возвращается приложению, и оно перезаписывает эту страницу новыми данными.

Можно просто поаплодировать тому, насколько это неэффективно. Думаю, можно с уверенностью сказать: писать через memory map — плохая идея, если важна производительность, особенно если есть риск, что файл ещё не загружен в физическую память.

Вот несколько бенчмарков:

Запись через mmap, страницы не в памяти: 1870 ns/op
Запись через mmap, страницы в памяти: 79 ns/op
WriterAt: 303 ns/op


Как видно, наличие страниц в кэше критически влияет на производительность. WriterAt, использующий системный вызов pwrite, даёт куда более предсказуемые результаты.

Тем не менее, в начале Varnish Cache действительно писал через memory map. Как-то это срабатывало — в основном потому, что конкуренты тогда были гораздо хуже.

Источник

@go_for_devs
  • 👍 8
  • ❤ 5
  • 🔥 3
  • 👎 2
More from @go_for_devs
  1. Sep 30, 2026Тут больше не будет новостей, статей и постов про Go. Go-разработчику сейчас важнее не син…
  2. Apr 16, 2026⚡️ Anthropic выпустили Claude Opus 4.7 Cursor зафиксировал рост с 58% до 70% на своём бенч…
  3. Feb 11, 2026🥳 Состоялся релиз Go 1.26 В релиз вошли несколько заметных изменений: 1. Функция new тепе…
  4. Jan 29, 2026Post #116
  5. Jan 22, 2026Помните, осенью мы писали про запуск опроса Go Survey 2025. Так вот, вчера команда Go опуб…
  6. Jan 21, 2026Философский подход к бэкенду
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →