Большое использование памяти замедляет несвязанный код - PullRequest
0 голосов
/ 27 мая 2019

Я поддерживаю код для проекта Go, который читает и записывает большое количество данных, и в течение некоторого времени это делалось успешно. Недавно я внес изменение: CSV-файл с примерно 2 миллионами записей загружается в карту со значениями структуры в начале программы. Эта карта используется только в части B, но первая часть A выполняется. И эта первая часть уже работает заметно медленнее, чем раньше (время обработки увеличивается в четыре раза). Это очень странно, поскольку эта часть логики не изменилась. Я провел неделю, пытаясь объяснить, как это может произойти. Вот шаги, которые я предпринял (когда я упоминаю производительность, я всегда ссылаюсь на часть A, которая не включает время загрузки данных в память и фактически не имеет к этому никакого отношения):

  • Программа работала на сервере внутри контейнера Docker. Но я смог воспроизвести его на своем ноутбуке без контейнера: производительность действительно снижается по сравнению с тем, когда я запускаю его без данных из файла, загруженного в память.
  • На сервере было огромное количество оперативной памяти. Хотя очевидно, что при загрузке файла используется больше памяти, ограничения не устанавливаются. Я также не видел пиков или других странных моделей в использовании памяти и дискового ввода-вывода. Для этих проверок я использовал pprof, htop и iotop.
  • Когда данные загружены, но на карте задано значение ноль, производительность снова в порядке.
  • Загрузка данных в срез вместо карты снижает снижение производительности с x4 до x2 (но использование памяти более или менее такое же, как с картой).
  • Это заставило меня задуматься, а есть ли доступ к карте / срезу где-то в части А, хотя это не так. Карта хранится в поле типа структуры. Я проверил, и эта структура всегда передается по указателю (включая все процедуры). Создание глобальной переменной вместо поля указателя не решило проблему.
  • За пределами стандартной библиотеки существует одна зависимость. Проблема вызвана библиотекой? Это вынуждает собирать мусор. Отключение этого не имеет значения. Я обнаружил другую подобную библиотеку, которая не связана, и использование этой в качестве замены повышает производительность, но все же занимает больше времени, когда загружаются данные файла.

Здесь я построил метрики с данными в памяти и без них: enter image description here

Что может вызвать этот эффект или как я могу это выяснить?

1 Ответ

1 голос
/ 27 мая 2019

Так что, если я правильно понял, ваш поток будет выглядеть примерно так:

  1. Считать 2 миллиона строк из CSV в карту -> struct
  2. Запустить часть A (для которой не нужны данные из CSV)
  3. Выполнить часть B, используя данные из CSV

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

Вероятно, сборщик мусора обычно получает доступ к 2 миллионам структур на карте. В зависимости от того, какое значение имеет GOGC, компонент кардиостимулятора сборщика мусора может включаться чаще, когда увеличивается объем выделяемой памяти. Поскольку эта карта отложена для последующего использования, GC ничего не должен делать, но он требует циклов проверки данных независимо. Есть несколько вещей, которые вы можете сделать, чтобы проверить и объяснить это поведение - все эти вещи могут помочь вам исключить / подтвердить, замедляет ли сбор мусора вас.

  • Профилируйте код (очевидно, важный для диагностики) IIRC, профиль ЦП с большей готовностью показывает вмешательства GC
  • Попробуйте отключить сборку мусора (debug.SetGCPercent(-1))
  • Сохраните карту в sync.Pool. Этот тип предназначен для хранения вещей, которыми вы будете управлять вручную, и выхода за пределы обычных циклов GC.
  • Читайте CSV только тогда, когда вам нужно, не читайте его раньше «часть A»
  • Потоковый файл, вместо того, чтобы читать его на массивной карте. 2 миллиона строк, какова ценность чтения всего этого в памяти, а не чтения построчно?
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...