Технічно, чому процеси в Erlang ефективніші, ніж потоки ОС?


170

Характеристики Ерланга

З програми Erlang Programming (2009):

Паралельність Erlang - це швидка та масштабована. Його процеси легкі тим, що віртуальна машина Erlang не створює нитку ОС для кожного створеного процесу. Вони створюються, плануються та обробляються в VM, незалежно від базової операційної системи. Як результат, час створення процесу має порядок мікросекунд і не залежить від кількості одночасно існуючих процесів. Порівняйте це з Java та C #, де для кожного процесу створюється базовий потік ОС: ви отримаєте дуже конкурентоспроможні порівняння, при цьому Erlang значно перевершує обидві мови.

З програмування, орієнтованого на сумісність, в Ерланге (pdf) (слайди) (2003):

Ми спостерігаємо, що час, необхідний для створення процесу Ерланга, є постійним від 1 мкс до 2500 процесів; після цього вона збільшується до приблизно 3 мкс для до 30 000 процесів. Продуктивність Java та C # показана у верхній частині рисунка. Для невеликої кількості процесів потрібно близько 300 мкс для створення процесу. Створити більше двох тисяч процесів неможливо.

Ми бачимо, що до 30 000 процесів час для надсилання повідомлення між двома процесами Erlang становить приблизно 0,8 мкс. Для C # потрібно близько 50 мкс на повідомлення, аж до максимальної кількості процесів (що склало близько 1800 процесів). Java була ще гіршою, тому що до 100 процесів займало близько 50 мкс на повідомлення, після чого вона швидко збільшувалась до 10 мс на повідомлення, коли було близько 1000 процесів Java.

Мої думки

Я не повністю розумію технічно, чому процеси Ерланг настільки ефективніші в нересту нових процесів і мають значно менші сліди пам’яті за процес. І ОС, і Erlang VM повинні робити планування, контекстні комутатори та відслідковувати значення в регістрах і так далі ...

Просто чому потоки ОС не реалізовані так само, як процеси в Erlang? Чи повинні вони підтримувати щось більше? І навіщо їм більший слід пам’яті? І чому у них повільніший нерест і спілкування?

Технічно, чому процеси в Erlang ефективніші, ніж потоки ОС, якщо мова йде про нерест і спілкування? І чому потоки в ОС не можуть бути реалізовані та керовані таким же ефективним способом? І чому потоки ОС мають більший слід пам’яті, а також більш повільний нерест і зв’язок?

Більше читання


1
Перш ніж намагатися зрозуміти причину, чому гіпотеза правдива, потрібно встановити, чи справжня гіпотеза - наприклад, підкріплена доказами. Чи є у вас посилання на будь-які подібні порівняння, які демонструють, що процес Erlang насправді є більш ефективним, ніж (скажімо, потік Java на поточному JVM)? Або додаток C, який безпосередньо використовує процес ОС та підтримку потоку? (Останнє здається мені дуже і дуже малоймовірним. Перший лише дещо вірогідний.) Я маю на увазі, що з досить обмеженим оточенням (точка Франсіско) це може бути правдою, але я хотів би побачити цифри.
TJ Crowder

1
@Donal: Як і у багатьох інших абсолютних тверджень. :-)
TJ Crowder

1
@Jonas: Дякую, але я дійшов до дати (1998-11-02) та версії JVM (1.1.6) і зупинився. За останні 11,5 років Sun JVM помітно покращився (і, мабуть, і перекладач Ерланга), особливо в області нарізування різьби. (Щоб було зрозуміло, я не кажу, що гіпотеза не відповідає дійсності [і Франциско і Дональ вказали, чому Ерланд може зробити щось там]; Я кажу, що це не слід сприймати за номінал без перевірки.)
TJ Crowder

1
@Jonas: "... але я думаю, ти можеш це зробити в Ерланге ..." Це та "здогадка", чувак. :-) Ви здогадуєтесь, що перемикання процесу Ерланга масштабується за тисячі. Ви здогадуєтесь, що це робить це краще, ніж теми Java або OS. Відгадування та програмне забезпечення не є чудовим поєднанням. :-) Але я думаю, що я зробив свою думку.
TJ Crowder

17
@ TJ Crowder: Встановіть erlang і запустіть erl +P 1000100 +hms 100і, а потім наберіть {_, PIDs} = timer:tc(lists,map,[fun(_)->spawn(fun()->receive stop -> ok end end) end, lists:seq(1,1000000)]).і зачекайте приблизно три хвилини на результат. Це так просто. На мій ноутбук потрібно 140 літрів за процес і 1 ГБ оперативної пам’яті. Але це безпосередньо оболонка форми, вона повинна бути краще від складеного коду.
Hynek -Pichi- Vychodil

Відповіді:


113

Є кілька факторів, що сприяють:

  1. Ерланг-процеси - це не процеси ОС. Вони реалізовані Erlang VM за допомогою легкої моделі кооперативного різьблення (вигідна на рівні Ерланг, але під контролем запланованого часу спільного виконання). Це означає, що набагато дешевше перемикати контекст, оскільки вони перемикаються лише у відомих, контрольованих точках і тому не потрібно зберігати весь стан процесора (звичайні регістри SSE та FPU, відображення адресного простору тощо).
  2. Ерланг-процеси використовують динамічно розподілені стеки, які починаються дуже малі і ростуть у міру необхідності. Це дозволяє нерестувати багато тисяч - навіть мільйонів - процесів Erlang, не висмоктуючи всю наявну оперативну пам’ять.
  3. Ерланг був однопоточним, це означає, що немає необхідності забезпечити безпеку потоку між процесами. Тепер він підтримує SMP, але взаємодія між процесами Erlang на одному і тому ж планувальнику / ядрі все ще дуже легке (на ядро ​​є окремі черги запуску).

6
До вашого другого пункту: І якщо процес ще не запустився, немає підстав для виділення для нього стека. Крім того: кілька хитрощів можна зіграти, поводячись з GC процесу, який ніколи не збирає пам'ять. Але це вдосконалено і дещо небезпечно :)
Я даю відповіді на решти

3
До вашого третього пункту: Erlang застосовує незмінні дані, тому введення SMP не повинно впливати на безпеку потоку.
nilskp

@ nilskp, це правильно, erlang - це також функціональна мова програмування. Тому немає "змінних" даних. Це призводить до безпеки потоку.
liuyang1

6
@nilskp: (RE: ви коментуєте пункт 3…) Навіть незважаючи на те, що сама мова має систему непорушних типів, основна реалізація - передача повідомлень, планувальник тощо - зовсім інша історія. Правильна та ефективна підтримка SMP відбулася не просто одним натисканням перемикача.
Марсело Кантос

@rvirding: Дякую за уточнююче доповнення. Я взяв на себе сміливість інтегрувати ваші пункти в основу моєї відповіді.
Марсело Кантос

73

Після ще кількох досліджень я знайшов презентацію Джо Армстронга.

Від Erlang - програмне забезпечення для спільного світу (презентація) (за 13 хв):

[Erlang] є одночасною мовою - маючи на увазі, що потоки є частиною мови програмування, вони не належать до операційної системи. Це дійсно не так у мовах програмування, таких як Java та C ++. Їх потоки не є мовою програмування, потоки - це щось в операційній системі - і вони успадковують усі проблеми, що виникають в операційній системі. Однією з проблем є деталізація системи управління пам’яттю. Управління пам'яттю в операційній системі захищає цілі сторінки пам'яті, тому найменший розмір, який може бути потоком, - це найменший розмір сторінки. Це насправді занадто велике.

Якщо ви додасте більше пам’яті на свою машину - у вас однакова кількість біт, яка захищає пам’ять, щоб деталізація таблиць сторінок зростала - ви в кінцевому підсумку використовуєте, скажімо, 64 кБ для процесу, який ви знаєте, працює в кілька сотень байт.

Я думаю, що це дає відповідь, якщо не все, то хоча б кілька моїх запитань



2
Захист пам’яті на стеках є з причини. Чи Erlang просто не захищає стеки різних контекстів виконання через MMU процесора? (І просто сподіватися на краще?) Що робити, якщо нитка використовує більше, ніж її крихітний стек? (Чи перевіряються всі розподіли стеків, щоб побачити, чи потрібен більший стек? Чи є стек рухомим?)
Thanatos

2
@Thanatos: Ерланг не дозволяє програмам отримувати доступ до пам'яті або поспілкуватися зі стеком. Усі асигнування повинні пройти керований час виконання, як купу, так і стек. Іншими словами: апаратний захист марний, оскільки захищає від речей, які так чи інакше не можуть трапитися. Мова захищена вказівниками, безпечною для зберігання даних, безпекою пам’яті та типом. Процес не може використовувати більше, ніж його "крихітний стек", тому що стек росте в міру необхідності. Ви можете думати про це як протилежне крихітному: нескінченно великому. (Але ліниво виділено.)
Jörg W Mittag

4
Слід поглянути на операційну систему сингулярності Microsoft Research. У сингулярності весь код, ядро, драйвери пристроїв, бібліотеки та користувацькі програми працюють в кільці 0 з повними правами ядра. Весь код, ядро, драйвери пристроїв, бібліотеки та користувацькі програми працюють у єдиному плоскому фізичному адресному просторі, без захисту пам'яті. Команда виявила, що гарантії, які надає мова, набагато сильніші, ніж гарантії, які може дати MMU, і в той же час використання MMU коштувало їм до 30% (!!!) у виконанні. Отже, навіщо використовувати MMU, якщо ваша мова все одно це робить?
Йорг W Міттаг

1
Операційна система OS / 400 працює так само. Існує лише один плоский адресний простір для всіх програм. І більшість мов, які фактично використовуються сьогодні, мають однакові властивості безпеки (ECMAScript, Java, C♯, VB.NET, PHP, Perl, Python, Ruby, Clojure, Scala, Kotlin, Groovy, Ceylon, F♯, OCaml, "Об'єктивна" частина "Objective-C", "++" частина "C ++"). Якби не старий код C та застарілі функції C ++ та Objective-C, нам навіть більше не потрібна віртуальна пам'ять.
Йорг W Міттаг

47

Я реалізував супроводи в асемблері та виміряв продуктивність.

Для перемикання між супрограмами, відомими також як Erlang-процеси, на сучасний процесор потрібно 16 інструкцій та 20 наносекунд. Крім того, ви часто знаєте процес, на який ви переходите (наприклад: процес, який отримує повідомлення у своїй черзі, може бути реалізований як прямий відхід від процесу виклику до процесу отримання), щоб планувальник не грав у дію, а це операція O (1).

Для перемикання потоків ОС потрібно приблизно 500-1000 наносекунд, тому що ви викликаєте до ядра. Планувальник потоків ОС може запускатися через час O (log (n)) або O (log (log (n))), який почне помітно, якщо у вас є десятки тисяч, а то й мільйонів потоків.

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


33

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

З іншого боку, потоки ОС можуть бути просто заплановані на різних ядрах процесора, і вони (в основному) здатні підтримувати незалежну процесорну обробку. Процеси ОС схожі на потоки ОС, але з набагато сильнішим розділенням на основі ОС. Ціна цих можливостей полягає в тому, що потоки ОС і (тим більше) процеси дорожчі.


Ще один спосіб зрозуміти різницю - це такий. Припустимо, що ви збираєтесь написати реалізацію Erlang поверх JVM (не особливо шалена пропозиція), тоді ви зробите кожен процес Erlang об’єктом з певним станом. Потім у вас буде пул екземплярів теми (типово розмір відповідно до кількості ядер у вашій хост-системі; це налаштований параметр у реальному режимі виконання Erlang BTW), який запускає процеси Erlang. У свою чергу, це розподілить роботу, яка повинна бути виконана через наявні реальні ресурси системи. Це дуже акуратний спосіб робити речі, але покладається повністюз приводу того, що кожен окремий процес Ерланг робить не дуже багато. Це нормально, звичайно; Ерланг побудований таким чином, щоб не вимагати, щоб ці індивідуальні процеси були важкими, оскільки саме цей ансамбль виконує програму.

Багато в чому справжня проблема - одна з термінологічних. Речі, які Ерланг називає процесами (і які сильно відповідають одній і тій же концепції в CSP, CCS і, зокрема, π-обчисленнях), просто не є такими ж, як речі, що володіють мовами зі спадщиною C (включаючи C ++, Java, C # і багато інших) викликають процес або потік. Є деякі схожість (усі пов'язані з поняттям одночасного виконання), але рівнозначності точно немає. Тому будьте обережні, коли хтось скаже вам «обробляти»; вони можуть зрозуміти, що це означає щось зовсім інше ...


3
Ерланг не наближається до Pi Calculus. Підрахунок Pi передбачає синхронні події по каналах, які можуть бути пов'язані зі змінними. Така концепція зовсім не відповідає моделі Ерланг. Спробуйте приєднатися до Calculus, Ерланг ближче до цього, хоча йому все ще потрібно мати можливість приєднатися до деяких повідомлень і чогось іншого. Була присвячена дисертація (та проект) з назвою JErlang, який її реалізував.
Я даю грізну пораду

Все залежить від того, яким саме ви бачите пі-числення (і ви можете моделювати асинхронні канали із синхронними каналами плюс буферними процесами).
Стипендіати Доналу

Ви просто говорите, що процеси Erlang легкі, але ви не пояснюєте, чому вони мають менший слід (вони легкі) і чому вони мають кращу продуктивність, ніж потоки ОС.
Йонас

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

Теоретично, ви могли б зробити потік ОС дуже дешевим і за допомогою дуже невеликого стека та ретельного контролю кількості інших виділених ресурсів, але це практично проблематично. (Прогнозувати вимоги до стеку - це трохи чорне мистецтво.) Тому замість потоків ОС спеціально розроблені як оптимальні в тому випадку, коли їх менше (на порядок кількості ядер CPU) і де вони роблять більш значущими обсяги обробки кожного.
Стипендіати Доналу

3

Я думаю, що Йонас хотів отримати деякі цифри щодо порівняння потоків ОС з процесами Ерланг. Автор програмування Ерланг, Джо Армстронг, якийсь час назад перевіряв масштабність нерестування процесів Ерланга до потоків ОС. Він написав простий веб-сервер в Ерланг і протестував його на багатопотоковому Apache (оскільки Apache використовує потоки ОС). Існує старий веб-сайт з даними 1998 року. Мені вдалося знайти його лише один раз. Тому я не можу надати посилання. Але інформація є там. Основний пункт дослідження показав, що Apache максував трохи менше 8K процесів, тоді як його написаний від руки сервер Erlang обробляв 10K + процеси.


5
Я думаю, ви говорите про це: sics.se/~joe/apachevsyaws.html Але я запитав, як erlang робить нитки настільки ефективними порівняно з потоками kerlenl.
Йонас

Посилання @Jonas мертве. Останній знімок тут
alvaro g

1
У статті сказано: "Apache помирає приблизно в 4000 паралельних сеансів. Звіса все ще функціонує при більш ніж 80 000 паралельних з'єднань".
Натан Лонг

дивіться повну статтю на сайті citeseerx.ist.psu.edu/viewdoc/… Дійсно, зламати сервер Erlang за допомогою 16 атакуючих машин виявилося неможливим - хоча сервер Apache було легко зупинити.
Бернхард

1

Оскільки інтерпретатору Ерланга доводиться турбуватися лише про себе, в ОС є ще багато чого турбуватися.


0

одна з причин полягає в тому, що процес erlang створюється не в ОС, а в evm (віртуальній машині erlang), тому вартість менша.

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