Язык программирования для функционального параллелизма: F # против Haskell - PullRequest
28 голосов
/ 31 марта 2011

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

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

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

ОБНОВЛЕНИЕ:

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

Ответы [ 7 ]

51 голосов
/ 31 марта 2011

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

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

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

21 голосов
/ 31 марта 2011

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

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

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

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

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

20 голосов
/ 31 марта 2011

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

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

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

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

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

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

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

12 голосов
/ 31 марта 2011

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

9 голосов
/ 09 апреля 2011

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

8 голосов
/ 31 марта 2011

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

6 голосов
/ 31 марта 2011

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

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

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

...