Вопрос

У меня есть программа Haskell, которая обрабатывает текстовый файл и создает Map (с несколькими миллионами элементов). Все это может бежать в течение 2-3 минут. Я обнаружил, что настроив варианты -h и -a вполне разница в течение времени.

Есть документация Об этой функциональности РТС, но это сложно читать для меня, так как я не знаю алгоритмы и термины из теории GC. Я ищу менее техническое объяснение, предпочтительно, специфичное для Haskell / GHC. Есть ли какие-либо ссылки о выборе разумных значений для этих вариантов?

Редактировать: Это код, он строит TRIE для данного списка слов.

buildTrie :: [B.ByteString] -> MyDFA 
buildTrie l = fst3 $ foldl' step (emptyDFA, B.empty, 1) $ sort $ map B.reverse l where
    step :: (MyDFA , B.ByteString, Int) -> B.ByteString -> (MyDFA , B.ByteString, Int)
    step (dfa, lastWord, newIndex) newWord = (insertNewStates, newWord, newIndex + B.length newSuffix) where            
        (pref, lastSuffix, newSuffix) = splitPrefix lastWord newWord
        branchPoint = transStar dfa pref

        --new state labels for the newSuffix path
        newStates = [newIndex .. newIndex + B.length newSuffix - 1]
        --insert newStates
        insertNewStates = (foldl' (flip insertTransition) dfa $ zip3 (branchPoint:init newStates) (B.unpack newSuffix) newStates)
Это было полезно?

Решение

Вообще говоря, сборка мусора - это пространство / время компромисса. Дайте GC больше места, и это займет меньше времени. Есть (много) другие факторы в пьесе, в частности, кэш, но промежуточное компромисс - самый важный.

The Communfoff работает, как это: программа выделяет память, пока она не достигла некоторого ограничения (определяется автоматическими параметрами настройки GC или явно через параметры RTS). Когда предел достигнут, GC прослеживает все данные, которые в настоящее время используют программу, и восстанавливает всю память, используемую по данным, которые больше не требуются. Чем дольше вы можете задержать этот процесс, тем временем появится дополнительные данные («Dead»), поэтому GC избегает отслеживания этих данных. Единственный способ задержать GC - значит получить больше памяти, чтобы выделить; Следовательно, больше памяти равна меньшем количестве GCS, равна нижним накладным расходам GC. Опция GHC GHC позволяет вам установить нижнюю границу в количестве памяти, используемого GC, поэтому может опустить накладные расходы GC.

GHC использует A. Genational GC., которая является оптимизацией к базовой схеме, в которой куча делится на два или более поколения. Объекты выделяются в «молодого» поколения, а также те, которые живут достаточно долго, получают продвижение в «старое» поколение (в установке 2 поколения). Молодое поколение собирается гораздо чаще, чем старое поколение, идея - это «большинство предметов умирают молодыми», поэтому коллекции молодого поколения дешевы (они не прослеживают много данных), но они восстанавливают много памяти. Грубо говоря, вариант -A устанавливает размер молодого поколения - то есть объем памяти, который будет выделен до того, как будет собираться молодого поколения.

По умолчанию для -а - 512K: это хорошая идея, чтобы молодое поколение меньше, чем кэш L2, а производительность обычно падает, если вы превышаете размер кэша L2. Но работа в противоположном направлении - это пространство GC / Time Tradeoff: использование очень большого размера молодого поколения может перевесить кеш преимуществ, уменьшая объем работы, который должен сделать GC. Это не всегда случается, это зависит от динамики приложения, что делает его трудно для GC автоматически настраивать себя. Опция -h также увеличивает размер молодого поколения, поэтому также может оказать неблагоприятное влияние на использование кеша.

Сутью является: воспроизведение с вариантами и посмотрите, что работает. Если у вас есть много памяти, чтобы посмотреть, вы вполне можете получить повышение производительности, используя либо -A или -H, но не обязательно.

Другие советы

Вероятно, можно воспроизвести проблему для меньших наборов данных, где будет легче увидеть, что происходит. В частности, я предлагаю получить некоторое знакомство с профилированием:

Затем проверьте, вы видите ли вы, что вы видите, сопоставьте ваши ожидания (вам не нужно знать обо всех вариантах профилирования, чтобы получить полезные графики). Сочетание строгого foldl' С не строгим кортежом, поскольку аккумулятор будет первым, что я бы смотрел: если компоненты кортежа не заставлены, что рекурсия создает нерешинные выражения.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top