Подтвердить что ты не робот

Функциональное программирование и многоядерная архитектура

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

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

Ответ 3

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

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

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

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

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

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

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

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

Ответ 4

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

Ответ 5

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

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

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

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

Ответ 6

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

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

Ответ 7

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

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

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

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

Ответ 8

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

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

Ответ 9

Книга Программирование Erlang: Программное обеспечение для параллельного мира Джо Армстронга (создатель Erlang) немного говорит об использовании Erlang для многоядерных (/многопроцессорных) систем, Как гласит статья Википедии:

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