Язык программирования для функционального parallelism: F # vs Haskell

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

F # имеет Microsoft за спиной, а его параллельные конструкции, такие как PLINQ, TPL, Async Workflow были хорошо документированы и показаны некоторые возможности. Тем не менее, исследование о parallelism в Haskell очень активно на данный момент, и оно обладает многими хорошими функциями, которые еще не поддерживались F #:

Мой вопрос - какой язык я должен выбрать для функционального parallelism? Если выбрано F #, есть ли какие-либо указатели для создания того, что у них есть в Haskell?

UPDATE:

Я выбрал Саймона, потому что это вызвало приятную дискуссию о сборщике мусора, распределении памяти и пропуске кеша. Я буду придерживаться F #, и я думаю, что эти ответы мне полезны для изучения функциональных parallelism.

7 ответов

Если тип кода, который вы имеете в виду, сильно выделяет память, тогда вы можете обнаружить, что сборщик мусора GHC масштабируется лучше, чем сборщик мусора .NET. Там anedcodal evidence, что .NET GC становится узким местом, когда много потоков распределяются сильно, и это также шип в стороне большинства сборщиков Java. С другой стороны, мы уделяем большое внимание достижению хорошей локальности и масштабируемости в сборщике мусора GHC - главным образом потому, что у нас нет выбора, большинство идиоматических Haskell-кодов в значительной степени распределяет. У меня есть контрольные показатели, которые выделяются как сумасшедшие и сохраняют масштабирование за пределами 24 ядер.

В Haskell обратите внимание, что вы получаете гарантию детерминизма от системы типов, которую вы не получаете в F #.

Вы упомянули Data Parallel Haskell: здесь предостережение, оно не готово к использованию в настоящее время, хотя команда DPH ожидает, что предстоящий выпуск GHC 7.2.1 будет иметь стабильную реализацию DPH.


Прежде всего, я согласен с другими, что нет объективного ответа.

Однако, я думаю, что идея функционального parallelism немного завышена. Разумеется, вы можете легко найти зависимости данных в своей программе, и если вы обрабатываете большое количество данных, вы можете использовать некоторую параллельную библиотеку данных, чтобы легко и безопасно ее распараллеливать. Однако это можно сделать даже в С# (используя TPL и PLINQ), если вы немного осторожны с тем, что пишете.

Проблема в том, что большинство программ не нужно распараллеливать, потому что они просто не выполняют достаточно интенсивной работы с ЦП. Например, F # async решает (я думаю) более важную проблему включения асинхронного ввода-вывода, что является причиной большинства "зависаний" в подключенных приложениях. Я думаю, что популярность Node.js очень хорошо демонстрирует это значение.

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

Чтобы ответить на ваш конкретный вопрос о parallelism - я считаю, что статус поддержки parallelism в F # более стабилен (но тогда я человек F #). Вы можете выбирать между асинхронными, TPL и (Erlang-inspired) агентами F # (которые являются довольно стабильными библиотеками). На стороне Хаскелла все еще происходит много эволюции. самая последняя работа - всего несколько недель. Мне также легче использовать parallelism на языке с четко определенной моделью оценки, но это может быть только мое личное предпочтение.


Я собираюсь занять это место, но позвольте мне быть кумиром.

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

Стоит отметить, что, несомненно, является самым успешным параллельно функциональным языком всех времен, Erlang, использует полностью болотно-стандартное сообщение, переходя к реализации его parallelism, и связь между его функциональной природой и ее parallelism является косвенной в лучшем случае.

Двадцать пять лет назад был огромный толчок для функциональных языков, потому что аргумент тогда казался очень убедительным, а функциональные языки казались естественным подспорьем для все более параллельных архитектур того времени. Аргумент заключался в том, что компиляторы и среды выполнения автоматически смогут реализовать parallelism из-за свободного характера побочных эффектов для языков. SISAL, который даже тогда мог быть скомпилирован в исполняемые файлы разделяемой и распределенной памяти (!), в это время, как и Haskell, как и ML, предшественник Objective CAML и другие lanaguages ​​в семействе ML.

Это всего лишь несколько историческая перспектива. В течение почти четверти века сторонники функционального языка, в том числе некоторые из самых ярких умов в этой области, говорили, что дневной день функциональных языков на солнце не за горами, и что он будет применим к parallelism Это приложение-убийца. И все же, вот мы здесь, никто даже не слышал о SISAL; и я предполагаю, что большинство читателей этого сообщения думают о Haskell как о горячем новом языке.

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

Огромное, огромное, подавляющее большинство параллельных и параллельных кодов, существующих сейчас, а также в обозримом будущем, не написано на функциональных языках. Если вы хотите узнать о parallelism, обязательно изучите механизмы, доступные в F #, Haskell и т.д.; но не ограничивай себя этим, все, что я говорю.


Простой ответ заключается в том, что, поскольку оба языка имеют надежную поддержку parallelism и concurrency, это не должно быть фактором в вашем решении о том, какой язык использовать. Например, для принятия такого решения есть более важные факторы >.


Нет объективного ответа. Для Haskell существует большой объем активной работы, и подход "одного размера не подходит всем". Вместо этого в Haskell предусмотрено множество различных инструментов для достижения parallelism. Каков статус многоядерного программирования в Haskell?


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

Это распространенное заблуждение. Parallelism относится исключительно к производительности и чистоте, что снижает производительность. Таким образом, чисто функциональное программирование не является хорошей отправной точкой, если ваша цель - добиться достойной производительности. В целом чистота означает большее распределение и худшую локальность. В частности, чисто функциональные структуры данных заменяют массивы деревьями и накладывают гораздо больше распределений и накладывают гораздо больше нагрузки на сборщик мусора.

Например, измерьте производительность элегантного чисто функционального "quicksort" в Haskell. Последнее, что я проверил, было в тысячи раз медленнее обычного императивного решения на моей машине.

Кроме того, никому не удалось реализовать эффективную структуру данных словаря (чистую или нечистую) или эффективную чисто функциональную сортировку в Haskell и никто не понял как написать асимптотически эффективную структуру постоянных непересекающихся наборов данных, и нет известного способа реализации других базовых структур данных, таких как чисто функциональные слабые словари!

Кроме того, хотя теоретически возможно писать нечистый код в Haskell, GC сильно оптимизирован для чистого кода за счет производительности мутации. Например, хеш-таблица GHC по-прежнему на 26 × медленнее, чем .NET. Исторически, производительность мутации считалась столь несущественной в Haskell, что писать один указатель на массив была операция O (n) в GHC в течение пяти лет.

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

Лучший способ, который я нашел, - научиться писать приличные параллельные программы для мультикорисов в императивном стиле (исследование Cilk, в в частности), а затем фактор кода, используя первоклассные функции и исключение хвостового вызова в нечистый функциональный стиль.

Это означает, что кэши не обращают внимания на структуры данных и алгоритмы. Никто никогда не делал этого в Haskell. Действительно, ни одно из исследований, опубликованных на параллельном Haskell, не упоминало о существенной концепции сложности кеша. Кроме того, хотя широко известно, что нестрогая оценка (aka lazy) делает непредсказуемое потребление пространства, еще не получила широкого распространения, что эта же проблема делает масштабируемость невероятно непредсказуемой на мультикодах.

F # имеет Microsoft за спиной, а его параллельные конструкции, такие как PLINQ, TPL, Async Workflow, были хорошо документированы и показали некоторые возможности.

Они намного превосходят потенциал. Тысячи коммерческих приложений основаны на этих промышленных прочных фундаментах.

Однако исследования о Parallelism в Haskell очень активны на данный момент, и у него есть много приятных функций, которые еще не поддерживаются F #:

Почему вы предполагаете, что они "хорошие функции"?

Я предлагаю прочитать последнюю статью Саймона Марлоу об этом:

"... сочетание практического опыта и исследования привело нас к выводу, что этот подход не лишен недостатков. В двух словах проблема заключается в следующем: достижение Parallelism с par требует, чтобы программист понял операционную свойства языка, которые в лучшем случае реализованы (и в худшем случае не определены), что затрудняет использование par, а ловушки изобилуют - у новых пользователей высокий коэффициент отказов..."

Мой вопрос в том, какой язык я должен выбрать для функционального parallelism?

Я бы посоветовал использовать параллельный чисто функциональный код для производства, потому что это полная дикая карта. Предполагая, что вы счастливы пожертвовать некоторой чистотой, чтобы достичь конкурентоспособности, я использую и рекомендую F #.


Чистота Хаскелла означает, что он делает четкое различие между параллельной обработкой и concurrency.

  • Если вы хотите ускорить работу своего большого хрустящего приложения, распределив работу по нескольким ядрам, вам потребуется параллельная обработка, что означает "пар" и его производные. Благодаря тщательному использованию этих конструкций вы можете использовать чистую функцию с интенсивным процессором в N раз быстрее на N ядрах, будучи уверенным, что вы не изменили значение исходного кода или не внесли в свою программу не детерминированность.

  • С другой стороны, если вы хотите, чтобы ваша программа взаимодействовала с несколькими объектами во внешнем мире, чередуя сообщения с разных сущностей, но все же имея некоторую степень общих ресурсов, тогда вы хотите concurrency, что означает использование "вилкой" и некоторой комбинацией STM и TVars. STM дает вам приятную транзакционную семантику, которая имеет большое значение для устранения условий гонки и других гадостей concurrency. Вы должны обратить внимание на частоту столкновений и частоту повторных попыток.

licensed under cc by-sa 3.0 with attribution.