Відмінність між "програмою" та "ниткою"?


Відповіді:


122

Супроводи - це форма послідовної обробки: лише одна виконується в будь-який момент часу (як і підпрограми AKA-функцій AKA-функцій - вони просто передають естафету між собою більш плавно).

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


188

Перше прочитання: Паралельність проти паралелізму - в чому різниця?

Паралельність - це відокремлення завдань щодо забезпечення переплетеного виконання. Паралелізм - це одночасне виконання декількох робіт з метою збільшення швидкості. - https://github.com/servo/servo/wiki/Design

Коротка відповідь: За допомогою потоків операційна система перемикає запущені потоки відповідно до свого планувальника, що є алгоритмом в ядрі операційної системи. За допомогою супроводу програміст і мова програмування визначають, коли слід перемикати супроводи; Іншими словами, задачі спільно виконуються за допомогою багатозадачних завдань призупинення та відновлення функцій у заданих точках, як правило (але не обов'язково) в межах одного потоку.

Довга відповідь: На відміну від потоків, які попередньо заплановані операційною системою, комутатори копрограми є спільними, тобто програміст (і, можливо, мова програмування та час його виконання) контролює, коли відбудеться перемикання.

На відміну від потоків, які є вигідними, перемикачі програм є спільними (програміст керує, коли відбудеться перемикання). Ядро не бере участь у перемикачах програми. - http://www.boost.org/doc/libs/1_55_0/libs/coroutine/doc/html/coroutine/overview.html

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

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

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

Супроводи та / або генератори можуть використовуватися для здійснення функцій кооперативу. Замість того, щоб запускатись на потоках ядра та планувати їх операційною системою, вони запускаються в один потік до тих пір, поки вони не поступаються чи не закінчуються, поступаючись іншим функціям, визначеним програмістом. Мови з генераторами , такими як Python та ECMAScript 6, можуть використовуватися для побудови кореневих програм. Асинхронізація / очікування (видно на C #, Python, ECMAscript 7, Rust) - це абстракція, побудована поверх функцій генератора, які дають ф'ючерси / обіцянки.

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

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

Наприклад, у Java були " зелені нитки "; це були потоки, які були заплановані віртуальною машиною Java (JVM) замість первісно на базових потоках ядра операційної системи. Вони не працювали паралельно або не скористалися декількома процесорами / ядрами - оскільки для цього знадобиться рідний потік! Оскільки вони не були заплановані ОС, вони були більше схожі на супроводи, ніж нитки ядра. Зелені нитки - це те, що використовувала Java до введення в Java 1.2 рідних потоків.

Нитки споживають ресурси. У JVM кожен потік має власний стек, зазвичай розміром 1 Мб. 64k - найменший обсяг місця в стосі, дозволений на один потік в JVM. Розмір стеки потоків можна налаштувати в командному рядку для JVM. Незважаючи на назву, потоки не є вільними, завдяки використанню таких ресурсів, як кожен потік, що потребує власного стека, локального зберігання потоків (якщо такий є) та вартості планування потоків / переключення контексту / недійсного кешу процесора. Це є причиною того, що супроводи стали популярними для критично важливих для виконання програм.

Mac OS дозволить лише процесу виділити близько 2000 потоків, а Linux виділяє стек 8 МБ на потік і дозволить лише стільки потоків, які вмістяться у фізичну оперативну пам'ять.

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


2
+1, але ця відповідь могла б отримати користь з деяких посилань.
kojiro

1
Зелені нитки - щось інше, ніж корутини. вони не так? Навіть волокна мають деякі відмінності. дивіться програмісти.stackexchange.com

113

Приблизно на 7 років, але у відповідях тут відсутній деякий контекст щодо спільної програми та потоків. Чому останнім часом супроводи приділяють стільки уваги, і коли я використовую їх порівняно з нитками ?

Перш за все, якщо супроводи виконуються одночасно (ніколи не паралельно ), чому б хтось віддав перевагу їм над потоками?

Відповідь полягає в тому, що супроводи можуть забезпечити дуже високий рівень одночасності з дуже невеликими витратами . Як правило, в потоковому середовищі у вас є щонайменше 30-50 потоків, перш ніж кількість витрачених накладних витрат фактично планує ці потоки (системним планувальником) значно скорочує кількість часу, що фактично виконує корисну роботу.

Гаразд, з потоками у вас може бути паралелізм, але не надто паралелізм, чи не все-таки краще, ніж спільний розпорядок роботи в одному потоці? Ну не обов’язково. Пам'ятайте, що спільний розпорядок роботи все ще може робити одночасність без накладних витрат - він просто керує самою комутацією контексту.

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

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

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

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

І нарешті, спільні програми приділяють багато уваги, оскільки в деяких мовах програмування (наприклад, Python) ваші потоки не можуть працювати паралельно - вони працюють одночасно, як і підпрограми, але без обмеженої пам'яті та вільного планування накладних витрат.


2
Як зробити перемикання на інше завдання в підпрограмах, коли ми стикаємося з операцією блокування?
Narcisse Doudieu Siewe

Спосіб переходу до іншого завдання полягає в тому, щоб будь-яка операція блокування фактично була виконана асинхронізацією. Це означає, що ви повинні уникати будь-якої операції, яка фактично блокує, і використовувати лише операції, які підтримують не блокування, коли вони використовуються у вашій системі кореневих програм. Єдиний спосіб цього полягає в тому, щоб підпрограми, які підтримуються ядром, такі як UMS в Windows, наприклад, коли воно скаче у ваш планувальник, коли ваша UMS "нитка" блокується на системному виклику.
retep998

@MartinKonecny ​​Чи дотримується останній TS C ++ Threads TS підходу, який ви згадали?
Нікос

Отже, зрештою, сучасній мові програмування знадобляться як Coroutines / Fibers, щоб ефективно використовувати одне ядро ​​процесора, наприклад, для операцій, що не обчислюють важкі операції, такі як IO і Threads, щоб паралелізувати інтенсивні операційні процеси на багатьох ядрах, щоб отримати швидкість, правда?
Mahatma_Fatal_Error

19

Одним словом: виплата. Корутини діють як жонглери, які продовжують передавати один одному добре відрепетовані бали. Нитки (справжні нитки) можна перервати майже в будь-якій точці, а потім відновити пізніше. Звичайно, це спричиняє всілякі проблеми конфлікту з ресурсами, отже, сумнозвісний GIL Python - Global Interpreter Lock.

Багато реалізацій потоків насправді більше схожі на спрощення.


9

Це залежить від мови, якою ви користуєтесь. Наприклад, у Lua - це те саме (називається змінний тип кореневища thread).

Зазвичай супроводи реалізують добровільну віддачу, де (ви) програміст вирішує, куди yield, тобто дати контроль іншому розпорядку.

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


0

На 12 років пізніше обговорення, але в кореневій програмі пояснення є в назві. Спрограму можна розкласти на Co та Rutine.

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

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

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

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

Не має значення, як спільні програми припиняють себе. Ще в Windows 3.1 int 03 було вплетено в будь-які програми (або їх потрібно було розмістити туди), а в C # ми додамо вихід.

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