Spec-Zone.ru › Haskell 9

5.4. Использование Concurrent Haskell

GHC по умолчанию поддерживает Concurrent Haskell без специальных параметров и библиотек, скомпилированных особым образом. Чтобы получить доступ к библиотекам поддержки Concurrent Haskell, просто импортируйте Control.Concurrent. Дополнительная информация о Concurrent Haskell приведена в документации этого модуля.

При желании программу можно скомпоновать с параметром -threaded (см. Параметры, влияющие на компоновку). Это даёт два преимущества:

  • Позволяет использовать -N ⟨x⟩, который даёт возможность потокам выполняться параллельно на многопроцессорной или многоядерной машине. См. Использование параллелизма SMP.
  • Если поток выполняет внешний вызов (и этот вызов не помечен как unsafe), другие потоки Haskell в программе продолжат выполняться, пока выполняется внешний вызов. Кроме того, функции Haskell, помеченные как foreign export, могут одновременно вызываться из нескольких потоков ОС. См. Многопоточность и FFI.

На поведение программ Concurrent Haskell влияют следующие параметры RTS:

-C ⟨s⟩
По умолчанию:

20 миллисекунд

Задаёт интервал переключения контекста в ⟨s⟩ секунд. Переключение контекста произойдёт при следующем выделении блока кучи после срабатывания таймера (блок кучи выделяется каждые 4k выделенной памяти). При использовании -C0 или -C переключение контекста будет происходить как можно чаще (при каждом выделении блока кучи).

5.5. Использование параллелизма SMP

GHC поддерживает параллельное выполнение программ Haskell на SMP-системах (с симметричной многопроцессорной архитектурой).

Между понятиями конкурентность и параллелизм есть важное различие: параллелизм позволяет сделать программу быстрее, используя несколько процессоров одновременно. Конкурентность же служит средством абстракции: это удобный способ организовать программу, которая должна реагировать на несколько асинхронных событий.

Однако эти понятия, безусловно, связаны. Используя несколько CPU, можно выполнять конкурентные потоки параллельно — именно это и делает поддержка параллелизма SMP в GHC. Но производительность можно повысить с помощью параллелизма и в программах, не использующих конкурентность. В этом разделе описано, как использовать GHC для компиляции и запуска параллельных программ; в разделе Параллелизм и конкурентность описаны языковые средства, влияющие на параллелизм.

5.5.1. Параметры компиляции для параллелизма SMP

Чтобы использовать несколько CPU, программу необходимо скомпоновать с параметром -threaded (см. Параметры, влияющие на компоновку). Кроме того, на параллелизм влияют следующие параметры компилятора:

-feager-blackholing

Blackholing — это пометка thunk (ленивого вычисления) как находящегося в процессе вычисления. Это полезно по трём причинам: во-первых, позволяет обнаруживать некоторые виды бесконечного цикла (исключение NonTermination); во-вторых, предотвращает некоторые виды утечки памяти; в-третьих, не позволяет повторно выполнять вычисление в параллельной программе, поскольку можно определить, что вычисление уже выполняется.

Параметр -feager-blackholing приводит к тому, что каждый thunk помечается как находящийся в процессе вычисления сразу же после начала вычисления. По умолчанию используется «ленивый blackholing»: thunk помечаются как находящиеся в процессе вычисления только при приостановке потока по какой-либо причине. Ленивый blackholing обычно эффективнее (примерно на 1–2%), поскольку большинство thunk не требуется помечать. Однако eager blackholing позволяет избежать большего количества повторных вычислений в параллельной программе, что часто оказывается важным для параллелизма.

Рекомендуем компилировать любой код, предназначенный для параллельного выполнения, с флагом -feager-blackholing.

5.5.2. Параметры RTS для параллелизма SMP

Запустить программу на нескольких процессорах можно двумя способами: вызвать в программе Control.Concurrent.setNumCapabilities или использовать параметры RTS -N ⟨x⟩.

-N ⟨x⟩
-N
-maxN ⟨x⟩

Использовать при запуске программы ⟨x⟩ потоков одновременно.

Среда выполнения управляет набором виртуальных процессоров, называемых capabilities; их количество задаётся параметром -N. Каждая capability может в каждый момент выполнять один поток Haskell, поэтому количество capabilities равно числу потоков Haskell, которые могут физически выполняться параллельно. Одну capability обслуживает один или несколько потоков ОС; среда выполнения управляет пулом потоков ОС для каждой capability, поэтому, если поток Haskell выполняет внешний вызов (см. Многопоточность и FFI), эту capability может занять другой поток ОС.

Обычно значение ⟨x⟩ следует выбирать в соответствии с числом ядер CPU на машине [1]. Например, на двухъядерной машине мы, вероятно, использовали бы +RTS -N2 -RTS.

Если опустить ⟨x⟩, то есть указать +RTS -N -RTS, среда выполнения выберет значение ⟨x⟩ самостоятельно, исходя из количества процессоров в вашей машине.

Если полностью опустить -N⟨x⟩, это означает -N1.

При использовании -maxN⟨x⟩, то есть +RTS -maxN3 -RTS, среда выполнения выберет не более (x), но не больше числа процессоров в системе. Указывать (x) обязательно; если нужно значение по умолчанию, используйте параметр -N.

Будьте осторожны при использовании всех процессоров вашей машины: если некоторые из них заняты другими программами, это может не улучшить, а ухудшить производительность. Запрашивать у GHC больше capabilities, чем имеется физических потоков, почти всегда неразумно.

Установка -N также включает параллельный сборщик мусора (см. Параметры RTS для управления сборщиком мусора).

Текущее значение параметра -N доступно из программы Haskell через Control.Concurrent.getNumCapabilities; его можно изменить во время выполнения программы, вызвав Control.Concurrent.setNumCapabilities.

Примечание

Максимальное число capabilities, поддерживаемое системой выполнения GHC, при запуске RTS устанавливается равным наибольшему из следующих значений: 256, значение, заданное параметром -N ⟨x⟩, или количество логических ядер CPU.

На способ планирования потоков средой выполнения на CPU влияют следующие параметры:

-qa

Использовать средства привязки ОС, чтобы попытаться закрепить потоки ОС за ядрами CPU.

Если этот параметр включён, потоки ОС для capability \(i\) привязываются к ядру CPU \(i\) с помощью API ОС для задания привязки потоков. Например, в Linux GHC использует sched_setaffinity().

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

-qm

Отключить автоматическую миграцию для балансировки нагрузки. Обычно среда выполнения автоматически распределяет потоки по доступным CPU, чтобы использовать простаивающие CPU; этот параметр отключает такое поведение. Обратите внимание, что миграция применяется только к потокам; балансировка sparks, создаваемых par, выполняется отдельно с помощью кражи работы.

Этот параметр, вероятно, полезен только для конкурентных программ, которые явно назначают потоки на CPU с помощью Control.Concurrent.forkOn.

5.5.3. Рекомендации по использованию параллелизма SMP

При запуске программы добавьте параметр RTS -s [⟨file⟩], чтобы увидеть статистику времени выполнения. Она поможет определить, стала ли программа работать быстрее при использовании большего числа CPU. Если пользовательское время больше прошедшего времени, программа использовала более одного CPU. Для сравнения следует также запустить программу без -N ⟨x⟩.

Вывод +RTS -s показывает, сколько «sparks» было создано и выполнено во время запуска программы (см. Параметры RTS для управления сборщиком мусора); это позволит оценить, насколько хорошо работают ваши аннотации par.

Поддержка параллелизма в GHC улучшилась в версии 6.12.1 благодаря многочисленным экспериментам и настройке системы выполнения. Нам по-прежнему интересно узнать, насколько хорошо она работает у вас; мы также хотели бы собрать параллельные программы, чтобы добавить их в набор тестов производительности.

[1]

Следует ли учитывать ядра с hyperthreading — вопрос открытый; экспериментируйте и расскажите нам о полученных результатах.

© 2002–2007 The University Court of the University of Glasgow. All rights reserved.
Licensed under the Glasgow Haskell Compiler License.
https://downloads.haskell.org/~ghc/9.14.1/docs/users_guide/using-concurrent.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API