Я поддерживаю код для проекта Go, который читает и записывает много данных и успешно работает в течение некоторого времени. Недавно я сделал изменение: файл CSV с примерно 2 миллионами записей загружается в карту со значениями структуры в начале программы. Эта карта используется только в части B, но выполняется первая часть A. И эта первая часть уже работает заметно медленнее, чем раньше (время обработки увеличено в четыре раза). Это очень странно, поскольку эта часть логики не изменилась. Я потратил неделю, пытаясь объяснить, как это может произойти. Вот шаги, которые я предпринял (когда я говорю о производительности, я всегда имею в виду часть А, которая не включает время загрузки данных в память и на самом деле не имеет к этому никакого отношения):
Здесь я построил метрики с данными в памяти и без них:
Что может вызвать этот эффект или как его узнать?
Два комментария. Во-первых, в чем конкретно заключается ваш вопрос? Хотите знать, как отследить утечку памяти? Во-вторых, вы не показали минимальный пример или код. Так что трудно догадаться, что происходит
"The server had a huge amount of RAM. Although obviously more memory is used when the file is loaded, no limits are hit
". Как насчет ограничения размера кеша процессора? Например. возможно, загрузка данных приводит к тому, что все остальные данные выталкиваются из кеша (и замедляет работу кода, использующего другие данные, из-за промахов кеша).
Обновил вопрос с метками на осях и явным вопросом.
@ Брендан Интересно, об этом я не подумал. Но я не верю, что это то, с чем я сталкиваюсь. Та часть кода, которая работает медленнее, состоит из чтения и записи файла без каких-либо предварительных данных.
Итак, если я правильно понял, ваш поток выглядит примерно так:
Зачем читать данные до того, как они вам понадобятся, был бы первый вопрос, но это, возможно, не имеет значения.
Вероятнее всего, сборщик мусора регулярно обращается к 2 миллионам структур на карте. В зависимости от того, какое значение имеет GOGC
, компонент стимуляции сборщика мусора, вероятно, будет срабатывать чаще по мере увеличения объема выделенной памяти. Поскольку эта карта отложена для последующего использования, сборщику мусора нечего делать, но в любом случае проверка данных занимает циклы. Есть ряд вещей, которые вы могли бы сделать, чтобы проверить и учесть это поведение - все эти вещи должны помочь вам исключить/подтвердить, замедляет ли вас сборка мусора.
debug.SetGCPercent(-1)
)sync.Pool
. Это тип, разработанный для того, чтобы вы могли хранить вещи, которыми вы будете управлять вручную, и выходить за рамки обычных циклов GC.Зачем читать данные до того, как они мне понадобятся: чтобы быстро выйти из строя (или предупредить), если они не ожидаемого формата.
Я прочитал 2 миллиона записей в памяти, потому что они не в том порядке, в котором они мне нужны. До сих пор я обходил проблему, читая записи, сортируя их и записывая снова (используя gob). Затем их можно удалить из памяти и передать в потоковом режиме.
Отключение сборки мусора действительно решило снижение производительности. Будет ли sync.Pool
предпочтительным решением для производственной среды? У меня много данных, которые нужно хранить в памяти на протяжении всего прогона.
@Socci: у меня недостаточно информации, чтобы сказать вам, является ли sync.Pool
лучшим решением здесь. Получение чего-либо из пула требует утверждений типа во время выполнения, поэтому вы можете в конечном итоге обернуть данные в тип и утвердить его для интерфейса, поэтому вам нужно сделать это только один раз, так что да, это может быть решением. Я бы тоже попробовал настроить значение GOGC
и сравнить
Не могли бы вы добавить метки к осям X и Y на графике?