Чому використання більшої кількості потоків робить це повільніше, ніж використання меншої кількості потоків


30

Спробував запустити програму X, використовуючи 8 ниток, і вона закінчилася за n хвилин .
Спробував запустити ту саму програму, використовуючи 50 ниток, і вона закінчилася за n * 10 хвилин .

Чому це відбувається і як я можу отримати оптимальну кількість потоків, які я можу використовувати?

Відповіді:


33

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

Чи процес / нитка

  • Процесорний зв'язок (потрібно багато ресурсів процесора)
  • Обмежена пам'ять (потрібно багато ресурсів ОЗУ)
  • Зв'язане введення / виведення (мережеві та / або ресурси жорсткого диска)

Усі ці три ресурси обмежені, і будь-який може обмежити продуктивність системи. Потрібно подивитися, на що (може бути 2 або 3 разом) ваша конкретна ситуація споживає.

Ви можете використовувати ntopі iostatта vmstatдіагностувати, що відбувається.


8
Обладнання теж має значення. Фізична, віртуальна, кількість ядер, тип ядра, кеш-пам'ять L1 / L2 / L3 тощо
EightBitTony,

46

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

Якщо у вас є 1-3 людини, то ви пропустите використання коридору. Якщо у вас є 5 і більше людей, то принаймні один з цих людей весь час затримується в черзі за іншою людиною. Якщо все більше людей просто засмічує коридор, це не прискорює активність.

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


1
Ваш приклад вводить в оману. Було б краще сказати щось на кшталт: "У вас є коридор, в який ви можете помістити чотирьох людей вниз, пліч-о-пліч, і ви його та інші люди використовуєте для різних завдань. Є суддя, який вирішує, хто може пройти коридор Тоді найефективніша кількість людей більша, ніж 4, і менша за якусь кількість, де ваші люди починають чергуватись [дуже залежно від контексту] ". Зазвичай наявність деяких потоків більше, ніж кількість процесорів, працює краще, ніж використання точно 4-х потоків. Якщо ви єдиний, хто використовує процесор, то 4це найкраще число.
Бакуріу

7
Чудовий приклад, +1. Бакуріу, його приклад, який ілюструє проблему обмеженого спільного ресурсу. Це пояснює проблему, а не як знайти оптимальну кількість ниток.
Bananguin

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

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

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

20

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

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


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

9

Як інші відзначали, ( ОДС відповідь , EightBitTony відповідь ) це складне питання , і тим більше, так як ви не описати те , що ви thred робити і як вони це роблять.

Але остаточне введення більше тем може погіршити ситуацію.

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

Суть закону Амдала полягає в тому, що в будь-якій програмі (в будь-якому алгоритмі) завжди є відсоток, який неможливо виконати паралельно ( послідовна частина ), і є ще один відсоток, який можна запустити паралельно ( паралельна частина ) [Очевидно ці дві порції складають до 100%].

Ця частина може бути виражена у відсотках від часу виконання. Наприклад, може бути 25% часу, витраченого на строго послідовні операції, а решта 75% часу витрачається на роботу, яка може виконуватися паралельно.

Зображення з Вікіпедії (Зображення з Вікіпедії )

Закон Amdahl передбачає, що для кожної заданої паралельної частини (наприклад, 75%) програми ви можете прискорити виконання лише поки що (наприклад, не більше 4 разів), навіть якщо для роботи використовуєте все більше процесорів.

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

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

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

  1. Обмежена швидкість введення / виводу (швидкість жорсткого диска та мережа)
  2. Обмеження розміру пам'яті
  3. Інші

що може бути обмежуючим фактором у практичних програмах.


Це повинна бути обрана відповідь.
Еоніл

6

Винуватцем тут має стати "КОНТЕКСТНЕ ВИМКНЕННЯ". Це процес збереження стану поточного потоку для початку виконання іншого потоку. Якщо ряд потоків мають однаковий пріоритет, їх потрібно перемикати, поки вони не закінчать виконання.

У вашому випадку, коли є 50 потоків, відбувається багато комутації контексту порівняно з просто запущеними 10 потоками.

Цього разу накладні витрати через зміну контексту - це те, що робить вашу програму повільною


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

Переключення контексту нитки саме по собі , якщо ми не маємо справу з величезною кількістю контекстних комутаторів, швидше за все, не матиме на порядок впливу на продуктивність. 50 ниток є високим, але не екстремальним (зараз у моєму вікні ps ax | wc -lповідомляється про 225 процесів, і він аж ніяк не сильно завантажений). Я схильний піти з здогадками @ EightBitTony; недійсність кешу, ймовірно, є більшою проблемою, оскільки кожен раз, коли ви стираєте кеш, процесору доводиться чекати еони для коду та даних з ОЗУ.
CVn

3

Щоб виправити метафору EightBitTony:

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

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

Тож ви хочете мати стільки людей, скільки може одночасно виконати певну роботу (використовувати відро) .

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

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

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

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


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

Насправді цей сценарій дуже схожий на стандартний опис взаємозв'язку між затримкою та розміром вікна в мережі TCP, тому він вискочив у мене.


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

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

0

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

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