Сучасна мова програмування з інтуїтивно зрозумілими одночасно абстракціями програмування [закрито]


40

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

Щоб навести кілька прикладів, я не вважаю хорошим варіантом написання багатопотокового коду на C, C ++ або Java, оскільки в IMHO моя продуктивність знижується, а їх модель програмування не є інтуїтивно зрозумілою. З іншого боку, мови, які підвищують продуктивність і пропонують більш інтуїтивні абстракції, такі як Python та багатопроцесорний модуль, Erlang, Clojure, Scala тощо, були б хорошими варіантами.

Що б ви порадили на основі свого досвіду і чому?

EDIT: Дякую всім за цікаві відповіді. Важко зробити висновок, не намагаючись насправді, оскільки є багато хороших кандидатів: Ерланг, Клуджуре, Скала, Гроові і, можливо, Хаскелл. Я проголосував відповідь найпереконливішими аргументами, але я спробую всіх хороших кандидатів, перш ніж вирішити, кого обрати :)


21
To give an example, I don't consider a good option writing multithreaded code in C, C++, or Java. Чому? On the other hand, Python and the multiprocessing module, Erlang, Clojure, Scala, etc. are some of my options.Знову ж чому? Розгорніть своє запитання, щоб краще визначити, що ви насправді шукаєте.
янніс

2
Тож ви хочете навчитися паралельному програмуванню з усіма дітьми або хочете приховати якусь його складність і зосередити увагу на продуктивності?
MaR

@MaR Зосередьтеся на продуктивності та
прихойте

Зауважте лише, що у багатьох із цих мов уникають багатьох важливих понять (деякі можуть сказати вирішеними), і тому C - це справді найкраща мова для вивчення паралельності. (Або, принаймні, мені так здається; я не знаю достатньо про всі перелічені мови). Підвищення продуктивності часто суперечить всебічному навчанню.
користувач606723

1
@DeadMG Зниження продуктивності - їхня проблема. Я не хочу зосереджуватися на синтаксисі мови замість проблеми. Я, безумовно, не хочу закінчувати боротьбу із тупиками. Як простий приклад, я хочу використовувати прості висловлювання, такі як, begin transaction end transactionі все, що знаходиться всередині, повинно бути беззахисним і в цілому мати успіх або збій.
sakisk

Відповіді:


33

Ви майже напевно повинні поглянути на Clojure - на мою думку, це найкраща сучасна мова для багатоядерного програмування, і це надзвичайно продуктивно.

Основні атрибути:

  • Це функціональна мова , яка є користю як для одночасності, так і для вашої здатності розвиватися за допомогою абстракцій вищого рівня. У ньому представлені повністю незмінні стійкі структури даних та ледачі послідовності, які будуть знайомі кожному, хто має досвід функціональних мов, таких як Haskell.
  • Він має дуже нову програмну систему оперативної пам'яті для одночасного безблокового доступу до змінного стану. Зробити безпеку для конкурентоспроможності коду часто так само просто, як загортати його в (dosync ....) блок.
  • Це Lisp - це робить його надзвичайно потужним для метапрограмування та генерації коду на основі макросу. Це може принести значні переваги в продуктивності (нарис Пола Грема - «Побиття середніх»)
  • Це мова JVM - тому ви не тільки отримуєте доступ до величезного масиву бібліотек та інструментів в екосистемі Java, ви також отримаєте користь від величезних інженерних зусиль, які зробили перетворення JVM на ефективну платформу для одночасних застосувань на сервері. Для практичних цілей це дає величезну перевагу перед мовами, які не мають такого фундаменту.
  • Це динамічно - це призводить до дуже стислого коду та великої продуктивності. Однак зауважте, що ви можете використовувати необов'язкові підказки статичного типу для продуктивності, якщо це необхідно.
  • Мова розроблена навколо абстракцій, що дещо важко пояснити, але чистий ефект полягає в тому, що ви отримуєте набір відносно ортогональних особливостей, які ви можете комбінувати для вирішення своїх проблем. Прикладом може слугувати абстракція послідовностей, яка дає змогу писати код, який стосується кожного "послідовного" типу об'єкта (який включає все, зі списків, рядків, масивів Java, нескінченних ледачих послідовностей, рядків, що читаються з файлу тощо).
  • Існує велике співтовариство - корисне, проникливе, але найголовніше дуже прагматичне - фокус у Clojure, як правило, на "завершенні справ".

Деякі зразки міні-коду з ухилом одночасності:

;; define and launch a future to execute do-something in another thread
(def a (future (do-something)))

;; wait for the future to finish and print its return value
(println @a)

;; call two functions protected in a single STM transaction
(dosync
  (function-one)
  (function-two))

Зокрема, варто переглянути одне або кілька таких відео:


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

8
Останнім часом мені довелося працювати з кодом JavaScript іншої розробника, і це найболючіша частина процесу: без типів аргументів функції, я повинен шукати всю базу коду, щоб з'ясувати, що вони повинні бути і що вони можуть робити на основі того, звідки їх покликано. Це не буде проблемою, якби JavaScript зберігав систему типів C на додаток до свого загального синтаксису.
Мейсон Уілер

1
@MasonWheeler: IMHO, якщо ви не можете зрозуміти, як викликати функцію без анотацій типу, це проблема з документацією (або її відсутність). Навіть у мовах, що набираються качками, зазвичай усе має задовольняти деяким обмеженням структурного типу (наприклад, повинно підтримувати арифметичні операції, повинно бути ітерабельним, повинне бути покажчивим тощо). Статичні типи допоможуть лише мінімально, оскільки вони не дадуть багато натяків на те, що функція виконує .
dimimcha

2
@Mason Я ніколи не говорив, що інших оголошень статичного типу не було. Насправді мені подобаються декларації статичного типу саме з тих причин, які ви заявляєте. Однак мені також подобається підвищення продуктивності динамічного набору тексту. Це компроміс. Якщо у вас хороший тестовий набір, я, як правило, вважаю, що це зменшує чимало недоліків динамічного введення тексту як з точки зору забезпечення коректності, так і надання прикладу коду, щоб допомогти новачкам зрозуміти правильне використання. YMMV.
mikera

1
@dsimcha - альтернативою проектуванню навколо абстракцій було б проектування навколо конкретної реалізації. Наприклад, більшість старих функцій Lisp працювали лише у зв'язаних списках, що зберігаються в комітках мінусів. Вам потрібні були різні функції для різних структур даних. У Clojure основна функція бібліотеки працює над чим-небудь послідовним (як у відповіді).
mikera

27

Ви можете спробувати D. Він пропонує три моделі. Я рекомендую або перше, або друге.

  1. ст.консульти . Якщо ви використовуєте цей модуль для всіх своїх потреб в одночасності, то поєднання мови та стандартної бібліотеки вимагає ізоляції між потоками. Нитки в першу чергу спілкуються через передачу повідомлень, з обмеженою підтримкою спільної пам'яті таким чином, що сприяє "безпеці спочатку" та забороняє перегони даних низького рівня. На жаль, документація std.concurrency потребує вдосконалення, але модель задокументована у вільній главі книги Андрія Олександреску "Мова програмування D".

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

  3. core.thread - це низькорівнева обгортка над специфічними для ОС API. Як std.concurrency, так і std.parallelism використовують його під кришкою, але я б рекомендував використовувати його лише в тому випадку, якщо ви пишете власну бібліотеку одночасності або знайдете якийсь смішний кутовий випадок, який неможливо зробити добре ні std.parallelism, ні std .конверсія. Ніхто не повинен використовувати щось таке низького рівня для щоденної роботи.


Вам слід було б згадати про незмінність / чистоту, локальне зберігання потоків за замовчуванням та спільне, що накладає мутацію в послідовному порядку. Thoses - це мовна підтримка, відсутня в C / C ++ для написання коду конкретного.
deadalnix

@deadalnix: Для мене більшість із них - це деталі моделі std.concurrency (як здійснюється ізоляція). Я хотів зберегти цю посаду лаконічною.
dimimcha

Ну насправді ні. Висновки вимагають як бібліотечної, так і мовної підтримки.
deadalnix

@deadalnix: Правильно, але вони були створені значною мірою для підтримки std.concurrency.
dimimcha

23

Ерланг - це, безумовно, чудовий варіант, але щось трохи практичніше може бути Go , новою мовою Google.

Це не так далеко від інших поширених мов, тому зазвичай це легко отримати, якщо ви вже знаєте інші "легкі" мови. Багато людей порівнюють його з Python або навіть Lua з точки зору того, наскільки «комфортно» це програмувати.


@faif запитує про прикладний / користувацький рівень, а не про одночасне програмування систем. Як Ерланг підходить до цього?
Хірон

@Raynos: Залежить від громади.
Стипендіати Дональ

@DonalFellows ваше право, я думаю, що моя заява була занадто вузькою
Райнос

1
@Chiron: Erlang - мова програмування, використовується для створення додатків. Як правило, багатопроцесорні програми. Я не знаю, куди він підходить як "паралельна система програмування", я не чув жодної ОС, написаної в Ерланге.
Хав'єр

1
Після швидкого огляду в підручнику Go, я хочу сказати, що IMHO - мова з C-подібним синтаксисом, який використовує (обмежені) покажчики, безумовно, не є сучасною мовою, що підвищує продуктивність.
сакіск

23

Погляньте на паралельне програмування Microsoft для .net. Це дуже інтуїтивно.

Багато персональних комп'ютерів та робочих станцій мають два-чотири ядра (тобто процесори), які дозволяють виконувати кілька потоків одночасно. Очікується, що в найближчому майбутньому комп'ютери матимуть значно більше ядер. Щоб скористатися обладнанням сьогодні та завтра, ви можете паралельно встановити код для розподілу роботи по декількох процесорах. Раніше паралелізація вимагала низького рівня маніпулювання нитками та замками. Visual Studio 2010 та .NET Framework 4 розширюють підтримку паралельного програмування, надаючи новий час виконання, нові типи бібліотеки класів та нові засоби діагностики. Ці функції спрощують паралельну розробку, так що ви можете записувати ефективний, дрібнозернистий та масштабований паралельний код у природній ідіомі без необхідності працювати безпосередньо з потоками чи пулом ниток. http://i.msdn.microsoft.com/dynimg/IC292903.png


+1 Це саме те, про що він просить. Хоча, коли виникають проблеми, важко буде їх налагодити, не розуміючи одночасності на нижчому рівні. Не кажучи вже про те, що сприйняття цього як початківця C # може виявитись… цікавим.
P.Brian.Mackey

@ P.Brian.Mackey - я згоден. Однак це не є рідкістю, не можна було б порівнювати це з використанням ORM, коли людина не повністю розуміє реляційну модель і SQL ...
Otávio Décio

1
Особливо PLINQ. Хоча це корисно лише для невеликого набору завдань, воно може бути дуже простим у використанні.
svick

21

І Ерланг, і Скала мають акторську одночасність , яку я вважав дуже інтуїтивно зрозумілою та легкою.

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


19

Я зараз дізнаюся про Haskell, і прочитавши цей документ переконав мене, що Haskell - це хороший варіант для одночасного програмування. Оскільки це суто функціонально (система типу знає, чи функція робить якийсь вхід, вихід чи читання / модифікацію глобального стану), вона може робити такі речі, як Оперативна пам'ять програмного забезпечення (підсумована дуже добре у вищенаведеному документі), яка поводиться аналогічно транзакціям в базах даних - ви отримуєте купу приємних речей, таких як атомність, лише трохи зайвого цукру. AFAIK, нитки Haskell теж дуже легкі. Крім цих речей, той факт, що Haskell є суто функціональним, дозволяє виконувати навіть прості завдання паралельно з трохи більше, ніж одним ключовим словом (номіналом). джерело


7

Мова Google GO має цікаві інструменти для одночасності - це було б ще однією цікавою справою. Дивіться: http://golang.org/doc/effective_go.html#concurrency і трохи прочитайте приклади.

Одночасне програмування є великою темою, і тут є місце лише для деяких особливостей, що стосуються Go.

Одночасне програмування у багатьох середовищах ускладнюється тонкощами, необхідними для здійснення правильного доступу до спільних змінних. Go заохочує інший підхід, при якому загальні значення передаються по каналах і насправді ніколи не діляться активно окремими потоками виконання. Лише одна goutut має доступ до значення в будь-який момент часу. За дизайном не може відбутися перегони даних. Щоб заохотити такий спосіб мислення, ми звели його до гасла:

Не спілкуйтеся, обмінюючись пам'яттю; натомість діліться пам’яттю, спілкуючись.

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

Один із способів думати про цю модель - розглянути типову однопоточну програму, що працює на одному процесорі. Він не потребує синхронізації примітивів. Тепер запустіть ще один такий екземпляр; воно також не потребує синхронізації. Тепер нехай ці двоє спілкуються; якщо комунікація є синхронізатором, все ще немає потреби в іншій синхронізації. Наприклад, трубопроводи Unix ідеально підходять до цієї моделі. Незважаючи на те, що підхід Go до одночасності бере свій початок в послідовних процесах, що передаються Хоаром (CSP), він також може розглядатися як безпечне узагальнення труб Unix ...


6

У наступній версії C # робить це навіть простіше, ніж це показано на схемі. Є два нові ключові слова Async та Await.

Async використовується як модифікатор функції і говорить, що "ця операція виконує свою роботу в іншій потоці.

Очікування використовується в рамках функції Async, і саме тут відбувається магія. В основному Очікуйте, повідомляє компілятору запустити операцію за ключовим словом в окремий потік і чекати результатів. Будь-який код після виклику очікування запускається після операції.

ТАКОЖ, операція синхронізується з викликовим потоком (тому, якщо ви виконуєте операцію асинхронізації у відповідь на натискання кнопки, вам не доведеться вручну відправляти повідомлення до потоку інтерфейсу). Дві маленькі ключові слова, і ви отримуєте багато сил паралельності. Детальніше читайте тут


Зверніть увагу, що будь-який гідний компілятор ОС C # вже підтримує C # 5, асинхронізуйте і чекайте.
Райнос

В основному Очікуйте, повідомляє компілятору запустити операцію за ключовим словом в окремий потік і чекати результатів. Цікаво, чи правильна ця відповідь - асинхронізація чекає не про нитки. Ця стаття пояснює приємно: немає
теми

Влучне зауваження. Я думаю, я говорив про це занадто просто. Те, що відбувається насправді, робиться "продовження", яке підписується на подію завдання в режимі "очікування". І так, певні операції вводу / виводу та thread.sleep () (які в основному відповідають на перерив годинника) не мають потоку. а як щодо завдань, зроблених вручну, які не мають вводу / виводу, як скажімо, ми зробили очікуваний калькулятор напруги? Технічно ця стаття є правильною: "Жодної теми немає", але насправді її ніколи не було, це завжди була концепція, яку ми використовували, щоб приховати деталі того, що робила для нас ОС.
Майкл Браун

6

Я все-таки рекомендую C ++. Більше ніж здатні необхідні абстракції написати гідний паралельний код. Переважаюча ймовірність полягає в тому, що у вас просто є бідна бібліотека для виконання цієї роботи, оскільки хороші бібліотеки для виконання цієї роботи є відносно новими, і справді знання про використання C ++ добре не є звичайним явищем. TBB від Intel існує лише кілька років, а PPL Microsoft постачається лише з минулого року.

Якщо ви використовуєте щось на кшталт TBB або PPL, тоді одночасний код - це не зовсім тривіально для запису, наскільки сумісність ніколи не є тривіальною, але далеко не важкою. Якщо ви використовуєте pthreads або Win32 нитки безпосередньо, то не дивно, що вам це не подобається - ви практично пишете в асемблері з такими функціями. Але з PPL, тоді ви говорите про стандартні функціональні алгоритми, паралелізовані для вас, загальні структури даних для паралельного доступу та подібні добрі речі.


1
Ознайомтеся з Boost.Threads або C ++ 0x std::thread(або std::tr1::thread). Це насправді дуже гарна абстракція, ІМО.
greyfade

1
@greyfade: Вони не мають абсолютно нічого в PPL або TBB. boost::threadце просто обгортка ОС з невеликим RAII. PPL та TBB - це реальні паралельні алгоритми, контейнери тощо
DeadMG

6

Тут потрібен штепсель для Ада , оскільки він має всі абстракції верхнього рівня для паралелізму та одночасності. інакше відомий як завдання . Крім того, як ОП попросив інтуїтивно зрозумілих (суб'єктивних критеріїв!), Я думаю, що інший підхід до світу, орієнтованого на Java, може бути оцінений.


5

Я б запропонував Groovy / Java / GPars, якщо ви можете бути на базі JVM, оскільки це дозволяє акторам, потоку даних, передачі послідовних процесів (CSP), паралелізму даних, транзакційної пам'яті програмного забезпечення (STM), агентів, ... Справа тут у тому, що там є багато моделей паралелізму та паралелізму на високому рівні, кожна з яких має різні "солодкі плями". Ви не хочете використовувати модель, яка не узгоджується з рішенням проблеми, яку ви намагаєтеся побудувати. Мови та структури лише з однією моделлю примушують вас до злому алгоритму.

Звичайно, мене можуть сприймати як упереджене, оскільки я беру внесок у Groovy та GPars. З іншого боку, я працюю з CSP і Python, пор. Python-CSP.

Наступним моментом є те, що початкове питання стосується навчання, а не написання виробничої системи. Тож комбінація Groovy / Java / GPars - це хороший спосіб навчання, навіть якщо майбутні виробничі роботи виконуються на C ++, використовуючи щось на кшталт Just :: Thread Pro або TBB, а не на базі JVM.

(Деякі цілком розумні посилання URL-адреси довелося видалити через деяку паніку щодо спаму від хост-сайту.)


Рассел, якщо ви хочете, ви можете сказати мені, що ви хочете пов’язати в кімнаті чату, і я додам їх вам: chat.stackexchange.com/rooms/21/programmers
Dan McGrath

4

А що з Clojure? Ви можете використовувати Swing, наприклад, але насолоджуєтесь програмою Cloture одночасно програмуванням? Clojure має досить гарну інтеграцію з Java.

Також ви розглядали рамки Java 7 Fork / Join ?


2

Ви також можете поглянути на Groovy та бібліотеку GPars . GPars BTW дещо схожий на .NET Parallel Extension, згаданий в іншій відповіді, але гнучкий синтаксис Groovys робить його читання краще в деяких умовах.


0

У запитаннях та відповідях про Scala згадували кілька разів, але я не бачив жодної згадки про Akka, яка є акторською реалізацією, яку можна використовувати як для Scala, так і для Java.


Що не так у цій відповіді? Жодна інша відповідь не згадує акку, і akka реалізує абстракцію високого рівня для одночасного програмування.
Джорджіо

-1

Я думаю, це залежить від того, що ти будуєш. Настільні програми чи сервер? Я чув, що (але не маю особистого досвіду) node.js чудово підходить для одночасного програмування для серверів (як з точки зору написання коду, так і з точки зору продуктивності). Якби я хотів написати новий серверний додаток, я, мабуть, спробував би це. Не впевнений у додатках для настільних комп’ютерів ... Я написав неабияку кількість речей у C # і є деякі інструменти, які добре приховують складність, хоча для інших випадків вам доведеться з цим стикатися.


-1

Я можу за це потрапити в голову, але ви читали розділ 7 TAOUP ? Розділ, про який я конкретно думаю, - це потоки проти процесів. Я виявив, що концепція одночасної обробки змушує більшість людей думати про теми, але я ніколи не бачив приклад, коли нитку простіше та швидше використовувати, ніж нерестування дочірнього процесу.

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

Знайдіть хорошу підпроцесорну бібліотеку, таку як посланник python . Або ви можете просто написати кілька окремих програм на C і написати ще одну "головну" програму, щоб використовувати fork і pipe для нересту і спілкування з підпроцесами.


3
Це протилежне тому, що ОП явно хоче… нерестовий процес настільки ж низький, як ірестовування нитки вручну. ОП зацікавлені у високому рівні абстракцій одночасності.
Конрад Рудольф
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.