Функціональне програмування та наукові обчислення


42

Прошу вибачення, якщо це неясне запитання, але ось що:

За останні кілька років функціональне програмування приділяло багато уваги спільноті Software Engineering. Багато хто почав використовувати такі мови, як Scala та Haskell і претендував на успіх у порівнянні з іншими мовами програмування та парадигмами. Моє питання: як високоефективні фахівці з обчислень / наукових обчислень, ми повинні бути зацікавлені у функціональному програмуванні? Чи варто брати участь у цій міні-революції?

Які плюси і мінуси функціонального програмування в галузі роботи SciComp?


2
Чому цілеспрямовано одягати себе в пряму куртку? Побічні ефекти - це засіб; це важливо для реальних програм. Якщо ви хочете, щоб ефективність процесора та пам'яті була потрібна, функціональні мови програмування не будуть на моєму радарі. Програми, які потребують автоматизованої перевірки / перевірки коректності (наприклад, для використання в ядерній установі?), Тоді добре, може бути випадок.
Черга учень

Відповіді:


34

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

Плюси:

  • Функціональне програмування виглядає дуже математично; це приємна парадигма для вираження деяких математичних понять
  • Є хороші бібліотеки для таких речей, як формальна перевірка програм і підтвердження теореми, тому можна писати програми, що міркують про програми - цей аспект корисний для відтворюваності
  • Ви можете виконувати функціональне програмування в Python та C ++ через лямбда-вирази; Ви також можете виконувати функціональне програмування в Джулії та Математиці
  • Користується не багатьма людьми, тож ви можете бути піонером. Так само, як і раніше були прихильники MATLAB, Python, R, а зараз Юлія, для того, щоб перейняти це, потрібно бути першими прийнятими функціонального програмування

Мінуси:

  • Мови, які, як правило, вважаються функціональними мовами програмування, як Haskell, OCaml (та інші діалекти ML) та Lisp, як правило, вважаються повільними щодо мов, що використовуються для критично важливих наукових обчислень. OCaml в кращому випадку приблизно вдвічі швидший, ніж C.
  • Ці мови не мають бібліотечної інфраструктури порівняно з мовами, які зазвичай використовуються в обчислювальній науці (Fortran, C, C ++, Python); якщо ви хочете вирішити PDE, це зробити простіше зробити це мовою, яка частіше використовується в обчислювальній науці, ніж тією, що це не так.
  • Існує не стільки обчислювальної наукової спільноти, яка використовує функціональні мови програмування, як і використання процедурних мов, а це означає, що ви не отримаєте багато допомоги, вивчаючи її чи налагоджуючи її, і люди, ймовірно, збираються давати вам лайно за використовуючи його (чи заслуговуєте ви цього чи ні)
  • Стиль функціонального програмування відрізняється від стилю, який використовується в процедурному програмуванні, який, як правило, викладається на вступних класах з інформатики та в класах типу "MATLAB для вчених та інженерів".

Я думаю, багато заперечень у розділі "Мінуси" можна було б подолати. Оскільки є поширеною точкою обговорення на цьому веб-сайті Stack Exchange, час розробника важливіший, ніж час виконання. Навіть якщо функціональні мови програмування повільні, якщо критично важливі для виконання частини можна делегувати на більш швидку процедурну мову і якщо підвищення продуктивності можна продемонструвати за допомогою швидкої розробки додатків, то їх, можливо, варто використовувати. Тут варто зауважити, що програми, реалізовані в чистому Python, чистому MATLAB і чистому R, значно повільніші, ніж реалізація цих же програм на C, C ++ або Fortran. Такі мови, як Python, MATLAB і R, популярні саме тому, що вони торгують швидкістю виконання для підвищення продуктивності, і навіть тоді, У Python та MATLAB є можливості реалізувати інтерфейси для компільованого коду в C або C ++, щоб критичний для продуктивності код міг бути реалізований для швидкого виконання. Більшість мов мають іноземний функціональний інтерфейс для C, якого було б достатньо для взаємодії з більшістю бібліотек, що цікавлять вчених-обчислювачів.

Якщо вас цікавить функціональне програмування?

Все залежить від того, що ти вважаєш класним. Якщо ви такий тип людини, який готовий дотримуватися конвенції, і ви готові пройти гасло євангелізації для людей про чесноти, що б ви не хотіли робити з функціональним програмуванням, я б сказав, що займіться цим . Я хотів би бачити, як люди роблять класні речі з функціональним програмуванням в обчислювальній науці, якщо ні з якої іншої причини, як довести, що всі найсайєри помиляються (а найсеерів буде багато). Якщо ви не тип людини, яка хоче мати справу з купою людей, які запитують вас: "Чому в пеклі ви використовуєте функціональну мову програмування замість (вставляйте сюди свою улюблену процедурну мову програмування)?", То я б не хотів ' t турбувати.

Існує деяке використання функціональних мов програмування для інтенсивної роботи з імітацією. Кількісна торгова фірма Джейн Стріт використовує OCaml для фінансового моделювання та виконання своїх торгових стратегій. OCaml також використовувався в FFTW для генерування деякого коду С, який використовується в бібліотеці. Liszt - мова, що використовується для домену, розроблена в Стенфорді та реалізована в Scala, яка використовується для вирішення PDE. Функціональне програмування, безумовно, використовується в промисловості (не обов'язково в обчислювальній науці); залишається зрозуміти, чи злетить вона в обчислювальній науці.


4
Я хотів би внести свій внесок у додавання Pro та Con. Pro :: гнучкість коду: оскільки все є функцією, ви завжди можете просто викликати цю функцію іншою функцією; це надзвичайно потужно. Con :: читабельність коду: функціональні коди програмування важко читати; навіть для (більшості) людей, які їх написали. Зараз мені навіть потрібен певний час, щоб зрозуміти деякі старі коди, які я написав, щоб вирішити деякі загальні проблеми PDE з B-сплайнами в Mathematica 6 місяців тому; Я завжди витягаю цей код, коли хочу налякати деяких колег ;-).
seb

4
Єдине доповнення, яке я хотів би додати: Con: Споживання пам'яті . Для усунення побічних ефектів потрібно зробити багато копіювання.
Меттью Емметт

1
@StefanSmith: (i) я знаю, що його іноді використовують у дослідженнях (наприклад, Maxima - CAS на базі Ліспа); окрім цього, я не знаю, що з голови. (ii) Поняття не має. Значна частина моєї відповіді ґрунтувалася на анекдотичних свідченнях, отриманих із розмов, які я мав за останні кілька років.
Джефф Оксберрі

@seb, це здається, що ви описуєте властивості функціональних мов, подібних до Lisp, які не так добре застосовуються до функціональних мов, подібних до Haskell.
Марк С.

1
Великий голос за коментар @MatthewEmmett. Копіювання може бути дуже дорогим для високоефективних обчислень.
Чарльз

10

У мене, можливо, є унікальна точка зору на це, тому що я є практиком HPC з науковим обчисленням, а також користувачем функціональної мови програмування. Я не хочу прирівнювати HPC до наукових обчислень, але перетин є чималим, і це є точкою зору, яку я приймаю, відповідаючи на це.

Наразі функціональні мови навряд чи будуть прийняті в HPC насамперед тому, що користувачі та клієнти HPC щиро дбають про досягнення максимально максимальної продуктивності. Це правда, що коли код пишеться функціонально, він, природно, виявляє паралелізм, який можна експлуатувати, але в HPC цього недостатньо. Паралелізм - це лише одна частина головоломки для досягнення високої продуктивності, ви також повинні враховувати широкий спектр мікро-архітектурних деталей, і для цього, як правило, потрібен дуже дрібний контроль над виконанням коду, щоб керування не було доступне в жодному функціональні мови, які я знаю.

Однак, я сподіваюся, що це може змінитися. Я помітив тенденцію, що дослідники починають усвідомлювати, що багато таких мікро-архітектурних оптимізацій можуть бути автоматизовані (певною мірою). Це створило зоопарк технології компіляції «джерело-джерело», де користувач вводить «специфікацію» обчислень, які вони хочуть відбутись, і компілятор виводить код C або Fortran, який усвідомлює, що обчислення з оптимізаціями та паралелізмом необхідні для ефективної роботи використовувати цільову архітектуру. Це, до речі, саме такі функціональні мови добре пристосовані для моделювання: моделювання та аналіз мов програмування. Не випадково перші великі користувачі функціональних мов були розробниками компіляторів. За кількома помітними винятками, я ще не бачив, щоб це насправді прийняло, але ідеї є,


8

Я хотів би додати один аспект до двох інших відповідей. Крім екосистеми, функціональне програмування надає чудову можливість для паралельного виконання, такого як багатопотокове чи розподілене обчислення. Притаманні йому незмінні властивості роблять його придатним для паралелізму, який, як правило, є справжнім болем у «відбійці», коли мова йде про імперативні мови.

Оскільки покращення продуктивності обладнання в останні роки було зосереджено на додаванні ядер до процесорів, а не на натисканні на більш високі частоти, паралельні обчислення набувають все більшої популярності (я думаю, ви це все знаєте).

Ще одна річ, про яку згадує Джефф, - це те, що час розробника часто важливіший, ніж час виконання. Я працюю в компанії, яка будує обчислювально інтенсивний SaaS, і ми зробили початковий тест на ефективність при запуску, піттінг C ++ проти Java. Ми з'ясували, що C ++ забезпечив приблизно 50% скорочення часу виконання над Java (це було для обчислювальної геометрії, і цифри, швидше за все, будуть змінюватися залежно від програми), але ми все одно з Java виходили через важливість часу розробника і сподівались, що оптимізація та майбутні покращення продуктивності обладнання допоможуть нам вийти на ринок. Я з упевненістю можу сказати, що якби ми вибрали інше, ми б все ще не працювали.

Гаразд, але Java не є функціональною мовою програмування, тож, що вона має відношення до чого-небудь, ви можете запитати. Ну а згодом, коли ми працювали з більшою кількістю прихильників функціональної парадигми і натрапляли на необхідність паралелізації, ми прогресивно перенесли частини нашої системи на Scala, яка поєднує позитивні сторони функціонального програмування з силою імперативу і добре зливається з Java. Це надзвичайно допомогло нам при збільшенні продуктивності нашої системи з мінімальним головним болем і, ймовірно, продовжить отримувати вигоду від подальшого підвищення продуктивності в апаратному бізнесі, коли в процесори завтра буде набито більше ядер.

Зауважте, що я повністю згоден з мінусами, згаданими в інших відповідях, але я вважав, що полегшення паралельного виконання є настільки потужним фактором, що воно не може не згадати.


8

Джефф вже дав хороший огляд причин, до яких я мало що додав, окрім наголосу на одному з його моментів: екосистемі. Незалежно від того, чи виступаєте ви за функціональне програмування або будь-яку іншу парадигму, одне з важливих питань, з яким ви маєте звернутись, - це те, що існує неймовірне кількість програмного забезпечення, яке можна створити на кожному іншому, що вам доведеться переписати. Прикладами є MPI, PETSc або Trilinos для лінійної алгебри, або будь-яка бібліотека кінцевих елементів - всі написані на C або C ++. У системі величезна кількість інерції, можливо, не тому, що всі думають, що C / C ++ насправді найкраща мова для написання обчислювального програмного забезпечення, а тому, що багато людей витратили роки свого життя, створюючи щось корисне для багато людей.

Я думаю, що більшість комп'ютерних людей погодиться з тим, що для спроб нових мов програмування та оцінки їх придатності до цієї проблеми є велика цінність. Але це буде важкий і самотній час, оскільки ви не зможете досягти результатів, конкурентоспроможних з тим, що роблять усі інші. Це також може створити вам репутацію того, хто розпочав наступний перехід до іншої парадигми програмування. Гей, на зміну Фортрану знадобилося лише С ++ приблизно 15 років!


6
А C ++ - у кращому випадку лише половина способу фактичної заміни Fortran у цьому просторі. Ми постійно бачимо нові коди у Fortran, і багато застарілого для завантаження!
Білл Барт

2
C ++ (на відміну від Фортран) є надто складним і для вивчення, і для використання. Нові наукові коди з відкритим кодом все ще пишуться у Фортран. Помітними в моєму регіоні (Науками про Землю) є PFlotran, SPECFEM3D, GeoFEM і т.д. IMHO C ++ навіть не замінив те, що потрібно було замінити (C).
stali

1
Ви повинні спробувати Фортран спробувати Вольфганг, це чудова мова, легко вивчити / записати, і швидкість не розчарує вас.
Ondřej Čertík

3
Мені не байдуже швидкість (ну, я роблю трохи, але це не всеохоплююче враження, що це стосується інших). Для мене важливо, скільки часу мені потрібно запрограмувати складний алгоритм, і Фортран програє на цьому фронті, оскільки мова така проста. Немає стандартної бібліотеки, про яку не можна говорити, немає шаблонів, які б дозволяли отримати загальний код, напівзрозумілу орієнтацію об'єкта. Фортран просто не є моєю мовою, і, чесно кажучи, це не повинно бути майже для всіх інших наукових людей, що займаються обчисленнями.
Вольфганг Бангерт

4
@StefanSmith: Так. Це може бути ідея, яку можна захищати в наукових обчисленнях (де я все ще стверджую, що вона застаріла і непродуктивна). Що стосується освіти студентів, то це, безумовно, не можна вважати - адже більшість наших студентів залишають академічні заклади, а в галузі практично ніхто не використовує Fortran.
Вольфганг Бангерт

7

Швидкий підсумок такий

  1. Числові обчислення використовують мутаційність / побічні ефекти для досягнення більшості його прискорень та зменшення виділень (багато функціональних структур програмування мають незмінні дані)
  2. Ледача оцінка може бути грубою для використання з числовими кодами.
  3. Або ви розробляєте пакет, де падіння вниз до найнижчих рівнів для виконання дійсно має значення (C / Fortran або зараз Julia) (в них ви також можете редагувати код асемблера за необхідності), або ви пишете сценарій, який використовує ці швидкі бібліотеки тому ви, як правило, дбаєте про час розробки (і тому ви обираєте Julia / MATLAB / Python / R). Функціональні мови, як правило, сидять на дивному середньому майданчику, що корисно в інших дисциплінах, але не так корисно тут.
  4. xnxn+1

Ці факти в сукупності роблять функціональне програмування не здається необхідним для більшості користувачів.


+1, але одне доповнення до пункту 3: Я вважаю, що функціональні функції в мовах високого рівня є досить корисними, і багато переваг функціональних мов, згаданих в інших відповідях (наприклад, легка паралелізація), як правило, стосуються цього сценарію.
Szabolcs

3

Я думаю, що цікаво відзначити, що використання функціонального програмування в обчислювальній науці не є новим. Наприклад, у цьому документі з 1990 р. Було показано, як покращити продуктивність чисельних програм, написаних на Ліспі (можливо, найбільш ранній функціональній мові програмування), використовуючи часткове оцінювання. Ця робота була частиною ланцюга інструментів, використовуваної у статті 1992 року Дж. Дж. Суссманом (про славу SICP ) та J Wisdom, що дала численні докази хаотичної поведінки Сонячної системи . Більш детальну інформацію про апаратне та програмне забезпечення, що беруть участь у цьому обчисленні, можна знайти тут .


1

R - це функціональна мова, а також мова статистики (і тепер Машинне навчання) і фактично мова № 1 для статистики. Це не мова HPC: вона не використовується для традиційного "стискання чисел", як фізичне моделювання тощо. Але це може бути зроблено для роботи на масивних кластерах (наприклад, через MPI) для масових статистичних моделей (MCMC) машинного навчання.

Mathematica - це також функціональна мова, але основна сфера - це символічні обчислення, а не обчислення чисельних.

У Julia ви також можете програмувати у функціональному стилі (поруч із процедурними та їх ароматом OO (мульти-диспетчеризація)), але це не чисто (базові структури даних є усіми змінними (крім кортежів), хоча є деякі бібліотеки з незмінними функціональні структури даних. Що ще важливіше, це набагато повільніше, ніж процедурний стиль, тому його не використовують багато.

Я б не назвав Scala функціональною мовою, а скоріше об'єктно-функціональним гібридом. У Scala можна використовувати багато функціональних понять. Scala важливий для хмарних обчислень через Spark ( https://spark.apache.org/ ).

Зауважте, що сучасний Fortran має фактично деякі елементи функціонального програмування: він має сувору семантику покажчиків (на відміну від C), ви можете мати чисті (без побічних ефектів) функції (і позначити його як таке), і ви можете мати незмінність. Він навіть має інтелектуальну індексацію, де можна задати умови для матричних індексів. Цей запит як і зазвичай зустрічається лише в мовах високого рівня, таких як R LINQ в C # або через функції фільтра вищого порядку на функціональних мовах. Таким чином, Fortran зовсім не такий поганий, що він навіть має деякі досить сучасні функції (наприклад, co-масиви), які не зустрічаються у багатьох мовах. Насправді, у майбутніх версіях Fortran я скоріше бачу більше функціональних функцій, а не OO-функцій (що зазвичай буває так), оскільки OO у Fortran справді незручний і некрасивий.


1

Плюси - це "інструменти", вбудовані в кожну функціональну мову: настільки легко фільтрувати дані, так легко перебирати дані і так набагато простіше розглянути чітке і стисле вирішення своїх проблем.

Єдиний кон - це те, що вам доведеться обіймати цей новий вид мислення: це може зайняти деякий час, щоб дізнатися, що ви повинні знати. Інші в домені SciComp насправді не використовують ці мови, а це означає, що ви не можете отримати таку велику підтримку :(

Якщо вас цікавлять функціонально-наукові мови, я розробив один https://ac1235.github.io


1

Ось мої аргументи, чому функціональне програмування може і потрібно використовувати для обчислювальної науки. Переваг величезна, і мінуси швидко проходять. У моїй думці є лише один мінус:

Con : відсутність мовної підтримки в C / C ++ / Fortran

Принаймні, на C ++, ця проблема зникає - оскільки C ++ 14/17 додав потужні засоби для підтримки функціонального програмування. Можливо, вам доведеться самостійно написати якийсь код бібліотеки / підтримки, але мова буде вашим другом. Як приклад, ось бібліотека (застереження: plug), яка робить незмінні багатовимірні масиви в C ++: https://github.com/jzrake/ndarray-v2 .

Також, ось посилання на хорошу книгу про функціональне програмування на C ++, хоча вона не зосереджена на наукових програмах.

Ось мій підсумок того, що я вважаю професіоналами:

Плюси :

  • Правильність
  • Зрозумілість
  • Продуктивність

З точки зору правильності , функціональні програми явно добре поставлені : вони змушують вас правильно визначити мінімальний стан змінних фізики та функцію, яка просуває цей стан вперед:

int main()
{
    auto state = initial_condition();

    while (should_continue(state))
    {
        state = advance(state);
        side_effects(state);
    }
    return 0;
}

Розв’язання часткового диференціального рівняння (або ODE) ідеально підходить для функціонального програмування; ви просто застосовуєте чисту функцію ( advance) до поточного рішення для створення наступного.

На мій досвід, програмне забезпечення для фізичного моделювання значною мірою обтяжене поганим управлінням державою . Зазвичай кожен етап алгоритму працює на деякому фрагменті спільного (фактично глобального) стану. Це ускладнює або навіть неможливо забезпечити правильний порядок операцій, залишаючи програмне забезпечення вразливим до помилок, які можуть виявлятися як seg-помилки, або ще гірше, помилки, які не руйнують ваш код, але мовчки ставлять під загрозу цілісність його науки вихід. Спроба керувати загальним станом у фізичному моделюванні також гальмує багатопотоковість - що є проблемою для майбутнього, оскільки суперкомп'ютери рухаються до більшої кількості ядер, а масштабування з MPI часто перевищує завдання на 100 к. На відміну від цього, функціональне програмування робить паралелізм спільної пам'яті тривіальним через незмінність.

Продуктивність також покращується у функціональному програмуванні завдяки лінивій оцінці алгоритмів (у С ++ це означає генерування багатьох типів за час компіляції - часто по одному для кожного застосування функції). Але це зменшує накладні витрати на доступ до пам'яті та їх розподіл, а також виключає віртуальну диспетчеризацію - дозволяє компілятору оптимізувати цілий алгоритм, побачивши відразу всі об'єкти функції, що його містять. На практиці ви експериментуєте з різними розташуванням балів оцінювання (де результат алгоритму кешується в буфері пам'яті) для оптимізації використання процесора та розподілу пам'яті. Це досить просто через високу локальність (див. Приклад нижче) етапів алгоритму порівняно з тими, які ти зазвичай бачиш у модулі або на основі класу коду.

Функціональні програми легше зрозуміти настільки, наскільки вони дорікають стан фізики. Це не означає, що їх синтаксис легко зрозумілий усім вашим колегам! Автори повинні обережно використовувати добре названі функції, а дослідники взагалі повинні звикати бачити алгоритми, виражені функціонально, а не процедурно. Я визнаю, що відсутність структур управління може перешкоджати деяким, але я не думаю, що це може перешкоджати нам іти в майбутнє, здатні робити якісніші науки на комп'ютерах.

Нижче наведена прикладна advanceфункція, адаптована з кінцево-об'ємного коду за допомогою ndarray-v2пакета. Зверніть увагу на to_sharedоператорів - це точки оцінки, на які я натякав раніше.

auto advance(const solution_state_t& state)
{
    auto dt = determine_time_step_size(state);
    auto du = state.u
    | divide(state.vertices | volume_from_vertices)
    | nd::map(recover_primitive)
    | extrapolate_boundary_on_axis(0)
    | nd::to_shared()
    | compute_intercell_flux(0)
    | nd::to_shared()
    | nd::difference_on_axis(0)
    | nd::multiply(-dt * mara::make_area(1.0));

    return solution_state_t {
        state.time + dt,
        state.iteration + 1,
        state.vertices,
        state.u + du | nd::to_shared() };
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.