2008-10-08 3 views
16

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

ответ

12

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

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

+1

Есть ли конкретные конкретные сравнительные примеры? – 2009-01-28 20:33:21

+0

@ja: Я критиковал некоторые из их недавних результатов тестов здесь: http://flyingfrogblog.blogspot.com/2010/06/regular-shape-polymorphic-parallel.html – 2010-06-05 10:31:37

6

Основной аргумент состоит в том, что трудно автоматически распараллелить такие языки, как C/C++/etc, поскольку функции могут устанавливать глобальные переменные. Рассмотрим два вызова функции:

a = foo(b, c); 
d = bar(e, f); 

Хотя Foo и бар нет аргументов общего и одного не зависит от кода возврата другого, тем не менее они могут иметь зависимости, потому что Foo может установить глобальную переменную (или другую сторону эффект), от которого зависит бар.

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

0

Опуская любые технические/научные термины, причина в том, что функциональная программа не передает данные. Данные копируются и передаются между функциями, поэтому в приложении нет общих данных.

И общие данные - это то, что вызывает половину головных болей при многопоточности.

+1

Функциональные программы почти всегда обмениваются данными. – 2010-06-27 19:59:33

1

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

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

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

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

12

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

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

Другим преимуществом является то, что некоторые процессы, которые очень легко распараллеливаются, подобно итерации, абстрагируются до функций.В C++ у вас может быть цикл for, который выполняет некоторую обработку данных по каждому элементу в списке. Но компилятор не знает, могут ли эти операции безопасно работать параллельно - возможно, результат одного зависит от того, который был до него. Когда используется функция типа map() или reduce(), компилятор может знать, что между вызовами нет зависимости. Одновременно можно обрабатывать несколько элементов.

+0

«Но компилятор не знает, могут ли эти операции безопасно работать параллельно». Означает ли это, что _ по умолчанию_ тот же цикл будет работать быстрее на функциональном языке, таком как Scala или Haskell, по сравнению с императивным языком? – Aventinus 2016-02-15 14:48:59

8

Если нет побочных эффектов, то порядок оценки не имеет значения. Затем можно оценивать выражения параллельно.

4

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

На практике я считаю, что свойство «без совместного использования изменяемого хранилища» на языках, основанных на сборке мусора и семантике копирования на замену, упрощает добавление потоков. Лучший пример - это, вероятно, Erlang, который объединяет почти функциональную семантику с явными потоками.

0

Книга Programming Erlang: Software for a Concurrent World от Joe Armstrong (создатель Erlang) довольно подробно рассказывает об использовании Erlang для многоядерных (многопроцессорных) систем. Как указано в статье в Википедии:

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

9

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

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

К сожалению, эта вера была давно опровергнуты по нескольким причинам:

  • The absolute performance of purely functional data structures is poor. Таким образом, чисто функциональное программирование - это большой начальный шаг в неправильном направлении в контексте производительности (что является единственной целью параллельного программирования).

  • Плотно функционирующие структуры данных сильно ухудшаются, поскольку они усиливают общие ресурсы, включая распределитель/GC и пропускную способность основной памяти. Поэтому параллельные чисто функциональные программы часто получают плохие ускорения по мере увеличения количества ядер.

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

Например, извращается two-line quicksort часто цитируется сообществом Haskell, как правило, работает в тысячи раз медленнее, чем реальное в быстрой сортировки на месте, написанной в более обычном языке, как F #. Более того, хотя вы можете легко распараллелить элегантную программу Haskell, вы вряд ли увидите какое-либо улучшение производительности, потому что все ненужное копирование делает одно ядро ​​насыщенным всей основной пропускной способностью памяти многоядерной машины, что делает параллелизм бесполезным. Фактически, никто никогда не мог написать какой-либо общий параллельный вид в Haskell, который является конкурентоспособным. Современные сорта, предоставляемые стандартной библиотекой Haskell, обычно в сотни раз медленнее обычных альтернатив.

Однако более распространенное определение функционального программирования как стиля, подчеркивающего использование первоклассных функций, действительно оказывается очень полезным в контексте многоядерного программирования, поскольку эта парадигма идеально подходит для факторинга параллельных программ. Например, см. Новую функцию верхнего разряда Parallel.For из пространства имен System.Threading.Tasks в .NET 4.

Смежные вопросы