Курсовая работа: Використання функціонального підходу при програмуванні розподілених задач для кластеру на прикладі технології DryadLINQ
Реалізація проекту Беовульф призвела до виникнення великої кількості послідовників, бо вона заклала основу для значно більш низьких за вартістю високопродуктивних обчислень. Прикладом може стати система Авалон, яка була зібрана в 98-му році і містила до 140 процесорів Alpha 21164A 533МГц. Його вартість становила приблизно 313 тисяч доларів, а продуктивність була на рівні суперкомп'ютера з 64-ма процесорами SGI Origon 2000, чия вартість була близько 1,8 мільйонів доларів. В 2000 році в top500 кількість кластерних рішень становило 2. 2%, в 2004 - 57,8%, а в 2009 - 81,2%. Динаміка розвитку представлена на Рис. 1. 1:
Рис. 1.1. Динаміка розвитку супер ЕОМ.
Під кластером тут розуміється обчислювальна система на архітектурі MPP (MassiveParallelProcessing) де засобами зв’язку між вузлами використовується Ethernet, Myrinet, InfiniBand або іншими відносно недорогими мережами. Як наслідок - повільний обмін між вузлами кластера. Тому в числі найважливіших робіт є розвиток паралельних обчислювальних технологій, а саме:
1. Розпаралелювання обчислень, створення нових методів та алгоритмів, орієнтованих на ефективне використання в багатопроцесорних системах, а також модернізація існуючих з реалізацією можливостей широкого паралелізму.
2. Розробка систем паралельного програмування, мовних та інших засобів із збереженням наступності прикладних програмних комплексів по відношенню до апаратних побудов розподіленої обчислювальної мережі.
3. Створення програмного забезпечення функціонування багатопроцесорних систем, у тому числі комунікаційної мережі обчислювальних модулів (ОМ) і між ОМ і зовнішніми абонентами.
4. Розробка архітектур багатопроцесорних обчислювальних систем. Інженерне конструювання ОМ та обчислювального поля в цілому.
5. Побудова і задіяння розподілених обчислювальних та інформаційних систем (кластерів робочих станцій, багатомашинних комплексів та ін.)
1.2 Функціональне програмування
Функціональне програмування (далі ФП) - наступний етап після імперативного програмування (ІП). Код написаний за допомогою ФП на відміну від ІП може звестися до декількох рядків, відповідно він легше читається та відлагоджується. Тобто тут основний акцент робиться на функції. Функціональне обчислення - функція (або якщо бути точніше - "чиста функція", pure function) - приймає вхідні аргументи на вході, робить певні обчислення і повертає деякий результат. При цьому функція не створює ніяких побічних ефектів. Під побічними ефектами розуміють:
- Змінювання глобальних (статичні в термінах C #) змінних або читати змінювані дані.
- Виклик інших функції які можуть створити побічний ефект або повернути глобальні змінні дані.
- Займатися будь-яким введенням / виводом
- Посилати або приймати будь-які повідомлення.
Три останні в загальному це зміна стану або читання змінюваного стану за допомогою виклику. Загалом, функція не має право робити нічого, що могло б змінити стан, і покладатися на змінні (ззовні) дані. Все, що робить функція - це обчислення і видача результату. У такого підходу є одна особливість: функція завжди повертає один і той же результат для одних і тих же аргументів. Це надає такі переваги:
- Легкість налагодження, адже функція залежить лише від параметрів. Весь стан при функціональних обчисленнях розташовується в стеці, так що його легко аналізувати, і навіть можна роботи покрокове скасування і повтор дій.
- Легкість розпаралелювання. Два виклики однієї і тієї ж функції абсолютно незалежні і можуть виконуватися паралельно. Крім того, потенційно виконання функції може бути автоматично распаралелено компілятором.
- Висока повторна використовуваних функцій. Тобто функцію легше використовувати в іншому місці програми (або в іншій програмі).
Фактично, відсутність побічних ефектів залежить не тільки від функції, а й від виразів що містяться в ній, тобто в них також потрібно не допускати побічних ефектів. В C# ФП реалізується завдяки LINQ або, як ще можна назвати, мова інтегрованих запитів. Ще одним з прийомів ФП (у порівнянні з ІП) є прийом передачі невеликого, так би мовити, уточнюючого, виразу в якусь універсальну функцію. C# (і більшість популярних.net-мов) не має конструкцій мови, що дозволяють відокремити чистий функціональний код від імперативного або змішаного.
Навіть старі імперативні мови, наприклад, C і Паскаль, підтримують базову ідею ФП - можливість маніпуляції функціями. Однак у більшості сучасних імперативних мовах реалізована ця можливість також погано. Зазвичай все обмежується можливістю передати вказівник на тіло функції. Скажімо, в С і C++ ім'я глобальної функції інтерпретується як вказівник на неї.
Функціональні мови (ФМ) розвивають цю ідею, зводячи її у принцип - функція є в програмі таким же повноцінним об'єктом, як і примірник будь-якого іншого типу (наприклад, екземпляр рядка). Її можна використовувати як звичайний об’єкт. Наприклад, в С ми можемо передати вказівник на функцію іншої функції, але скласти (під час виконання) з двох функцій третю ми не в силах. Неможливо в С і оголосити функцію по місцю. У ФМ ж все це можливо. Маніпулювати функціями в ФМ дуже просто і зручно. Для цього необхідний функціональний тип. Зазвичай він буде приймати вигляд string Function (int x, string y);
проте якщо замінити перечислення на "*", а для опису поверненого значення функції використати "->", тоді вищерозглянуту ф-ію можна описати: int * string - > string або int - > string - > string, отже функція яка отримує int і повертає функцію, яка отримує stringта повертає string. Даний вираз називається "лямбда виразом", та існує ціла теорія що обґрунтовує це.
Другою особливістю ФП у порівнянні з ІП є робота зі списками. У ФП список зазвичай видається за допомогою структури даних, як однонаправлений зв’язний список (далі просто список). Особливістю цієї структури даних є те, що вона дозволяє створювати незмінні списки. При цьому список має ряд обмежень:
- Він допускає додавання елементів тільки в початок списку.
- Видалення елементів неможливо (але, як і будь-який інший об'єкт у.net, елементи звільняються автоматично, якщо на них немає інших посилань).
- Для зберігання кожного елемента створюється окремий об'єкт.
- Доступ за індексом елемента можливий тільки перебором.
Дані обмеження роблять списки неефективними, якщо їх використовують в імперативній манері, але зручними і ефективними при програмуванні в функціональному стилі. На жаль, в.net немає реалізації однонаправленого пов'язаного списку (клас LinkedList <Of> є реалізацією двонаправленого пов'язаного списку). Застосування списків у ФП виправдане ще й тим, що в основному списки реалізуються в них у вигляді алгебраїчних типів даних. Це дозволяє здійснювати розбір списків з застосуванням зіставлення зі зразком. На жаль, поки немає ні одної імперативної мови програмування, що володіє подібною можливістю, так що це перевага поки не є доступною для тих, хто з тих чи інших причин не хоче скористатися функціональною мовою програмування для реалізації своїх завдань.
Імперативний код (ІК) - обробка послідовностей (списків) як послідовність перетворень, як це прийнято в ФП, тобто ІК сукупність циклів, та вся обробка послідовності це вмісти цих циклів. У ФП обробка списків розбивається на кілька простих перетворень, які можна виконати послідовно. Так як на кожній стадії обробки виходить (фактично) нова послідовність, налагодження такого коду стає вельми простим завданням у порівнянні з ІК. Крім того, читати такий код значно простіше.