Haskell облегченные потоки накладных расходов и использование на многожильных

Я читал книгу "Real World Haskell", главу concurrency и parallelism. Мой вопрос следующий:

  • Так как потоки Haskell на самом деле являются просто несколькими "виртуальными" потоками внутри одного "реального" OS-потока, значит ли это, что создание многих из них (например, 1000) не окажет существенного влияния на производительность? I.e., можно ли сказать, что накладные расходы, связанные с созданием потока Haskell с forkIO, (почти) незначительны? Если возможно, приведите примеры действий.

  • Разве концепция легких потоков не позволяет нам использовать преимущества многоядерных архитектур? Насколько я понимаю, невозможно, чтобы два потока Haskell выполнялись одновременно на двух отдельных ядрах, поскольку они представляют собой один единственный поток с точки зрения операционной системы. Или время выполнения Haskell делает некоторые хитроумные трюки, чтобы обеспечить использование нескольких процессоров?

Ответ 1

Время выполнения GHC обеспечивает среду выполнения, поддерживающую миллиарды искр, тысячи легких потоков, которые могут быть распределены по нескольким ядерным ядрам. Скомпилируйте с помощью -threaded и используйте флаги +RTS -N4, чтобы установить необходимое количество ядер.

sparks/threads/workers/cores

В частности:

означает ли это, что создание многих из них (например, 1000) не окажет существенного влияния на производительность?

Ну, создание 1 000 000 из них, безусловно, возможно. 1000 так дешево, что он даже не появится. Вы можете увидеть в тестах создания потоков, таких как "кольцо нитей", которое GHC очень, очень хорошо.

Разве концепция легких потоков не позволяет нам использовать преимущества многоядерных архитектур?

Совсем нет. GHC работает с multicores с 2004 года. Текущий статус многоядерной версии отслеживается здесь.

Как это делается? Лучшее место для чтения по этой архитектуре содержится в документе "Поддержка времени выполнения для многоядерного Haskell" :

Система времени выполнения GHC поддерживает миллионы легких потоков путем мультиплексирования их на несколько потоков операционной системы, примерно один для каждого физического процессора....

Потоки Haskell выполняются набором операционных систем потоков, которые мы называем рабочими потоками. Мы поддерживаем примерно один рабочий поток на физический процессор, но именно тот рабочий поток может меняться от момента к моменту...

Поскольку рабочий поток может меняться, мы поддерживаем ровно один Контекст исполнения Haskell (HEC) для каждого CPU. HEC - это структура данных, которая содержит все данные, которые рабочий поток ОС требуется для выполнения потоков Haskell

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

threadscope

Ответ 2

  • Веб-сервер Warp широко использует эти легкие потоки, чтобы получить действительно хорошую производительность. Обратите внимание, что другие веб-серверы Haskell также курят конкуренцию: это скорее "Haskell - это хорошо", чем "Warp is good".

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

Ответ 3

Создание 1000 процессов относительно легкое; не беспокойтесь об этом. Что касается производительности, вы должны просто сравнить ее.

Как уже указывалось ранее, несколько ядер работают нормально. Несколько потоков Haskell могут запускаться в одно и то же время, будучи запланированными на разных потоках ОС.