Почему функциональные языки считаются благом для многопоточных сред? - PullRequest
8 голосов
/ 26 мая 2010

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

Тем не менее, для меня это не имеет большого смысла, потому что почти все практические программы в реальном мире нуждаются / имеют состояние, о котором нужно заботиться. Мне также интересно, что большинство основных библиотек масштабирования, например MapReduce, обычно написаны на императивных языках, таких как C или C ++.

Я хотел бы услышать от функционального лагеря, откуда я слышу эту ажиотаж ...

Ответы [ 5 ]

13 голосов
/ 26 мая 2010

Важно добавить одно слово: «нет общего состояния».

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

7 голосов
/ 26 мая 2010

Функциональные языки, такие как Haskell, Scheme и другие, имеют так называемые «чистые функции». Чистая функция - это функция без побочных эффектов. Это не изменяет любое другое состояние в программе. Это по определению потокобезопасно.

Конечно, вы можете писать чистые функции на императивных языках. Вы также можете найти языки с несколькими парадигмами, такие как Python, Ruby и даже C #, где вы можете выполнять императивное программирование, функциональное программирование или оба.

Но смысл Хаскелла (и т. Д.) Состоит в том, что вы не можете написать не чистую функцию. Ну, это не совсем верно, но в основном это правда.

Точно так же многие императивные языки имеют неизменные объекты по той же причине. Неизменяемый объект - это объект, состояние которого не изменяется после создания. Опять же по определению неизменный объект является поточно-ориентированным.

6 голосов
/ 26 мая 2010

Вы говорите о двух разных вещах и не понимаете этого.

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

4 голосов
/ 26 мая 2010

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

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

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

Многие функциональные языки являются «нечистыми», что означает, что они допускают некоторое состояние. У Haskell нет, но у Haskell есть монады, которые в основном позволяют получить что-то из ничего: вы получаете состояние, используя конструкции без состояния. С монадами работать немного сложновато, поэтому Haskell дает вам мощный стимул ограничивать состояние настолько малой частью вашей программы, насколько возможно.

Мне также интересно, что большинство основных библиотек масштабирования, т.е. MapReduce, как правило, написаны на императивных языках, таких как C или C ++.

Программирование параллельных приложений в C / C ++ "сложно". Вот почему лучше всего делать все опасные вещи в библиотеке, которая тщательно проверена и проверена. Но вы все равно получаете гибкость и производительность C / C ++.

2 голосов
/ 26 мая 2010

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

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

Это всего лишь простой пример. Вы можете развить это. Функции для применения других функций к двумерным массивам, функции для применения функций к древовидным структурам, функции для объединения функций для применения функций (например, если у вас есть иерархическая структура с деревьями вверху и массивами ниже) и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...