Оптимальна кількість ниток на ядро


281

Скажімо, у мене є 4-ядерний процесор, і я хочу запустити певний процес за мінімальний проміжок часу. Процес ідеально паралельний, тому я можу запускати шматки його на нескінченну кількість ниток, і кожна нитка займає стільки ж часу.

Оскільки у мене є 4 ядра, я не сподіваюся на швидкість запуску більше потоків, ніж ядер, оскільки одне ядро ​​здатне запускати один потік в даний момент. Я мало знаю про обладнання, тому це лише здогадка.

Чи є користь від запуску паралельного процесу на більшій кількості потоків, ніж на ядрах? Іншими словами, чи завершиться процес швидше, повільніше або приблизно за стільки ж часу, якщо я запускаю його за допомогою 4000 потоків, а не 4 ниток?

Відповіді:


254

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

Не так давно я робив тестування продуктивності на 2-х чотирьохядерній машині, що запускає додаток ASP.NET на Mono під досить пристойним навантаженням. Ми грали з мінімальною та максимальною кількістю потоків, і врешті-решт ми з’ясували, що для цієї конкретної програми у цій конкретній конфігурації найкраща пропускна здатність була десь між 36 та 40 потоками. Все, що виходило за ці межі, діяло гірше. Урок вивчений? Якби я був ти, я б протестував з різною кількістю ниток, поки не знайдеш потрібний номер для своєї програми.

Одне напевно: 4 к нитки займуть більше часу. Це багато перемикачів контексту.


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

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

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

4
1 нитка на ядро ​​не є оптимальним. Це потрібно трохи більше, бажано вдвічі більше, оскільки це дозволить запустити інший потік, якщо потік тимчасово заблокований. Навіть якщо тільки на пам'ять. Це більше importnat, якщо у вас є системи (P4, I7, Sun Rock тощо), у яких є SMT / HT)
Марко ван де Ворт

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

129

Я згоден з відповіддю @ Гонсало. У мене є процес, який не робить I / O, і ось що я знайшов:

введіть тут опис зображення

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

Машина 1,86 - це повітряне середовище Macbook із SSD. Інший mac - це iMac з нормальним жорстким диском (я думаю, це 7200 об / хв). Машина Windows також має жорсткий диск 7200 об / хв.

У цьому тесті оптимальне число було рівним кількості ядер у машині.


14
+1 для графіка. Очевидно, що найкраще 1 потік на ядро, але цікаво, що система чотирьохядерних ядер, здається, не на більшій кількості потоків (<100 все одно), як це роблять інші.
Джим Гаррісон

46
-1 для графіка! Плавні криві через цілочисельні x-координати? Дикий стрибок від 1 2 3 до 10 20 30 до 50 100? І y-координати, кратні 10 плюс 2 для хорошої міри. Це Excel робить, чи не так?
Spacedman

5
@Spacedman Так. Гладкі криві мають набагато приємніший вигляд IMHO. : D
Мотасім

22
@PascalvKooten, Проблема не в тому, що це виглядає красиво, це обман з першого погляду. Перш за все вісь y починається з 42, перебільшуючи очевидну різницю між перевіреними машинами. По-друге, дивна прогресія значень осі x говорить про те, що "час, відведений", не лінійно масштабується з "кількістю потоків", це особливо стосується синьої лінії. Я думаю, що проблема, пов'язана з іншими (в тому числі і я), полягає в тому, що вона неправильно представляє дані.
pauluss86

13
@Spacedman Критика на графіку - це найсмішніша річ, з якою я стикався за останні 24 години. Графік допомагає. Багато. Період. Чи можна було це зробити краще? Всім байдуже. Плавна крива замість дискретної? Це ваша проблема ???? Я припускаю, що ви ніколи не включали б такий графік у свою відповідь, оскільки у вас немає зайвого часу / енергії, щоб він виглядав добре. Це моя думка.
tyrex

50

Я знаю, що це питання досить старе, але все розвивалося з 2009 року.

Зараз слід враховувати дві речі: кількість ядер та кількість потоків, які можуть працювати в кожному ядрі.

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

На інших процесорах у вас може бути 2, 4 або навіть 8 потоків. Отже, якщо у вас є 8 ядер, кожне з яких підтримує 8 потоків, у вас може бути 64 процеси, що працюють паралельно без переключення контексту.

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

З мого власного досвіду, якщо у вас багато вводу / виводу, корисні кілька потоків. Якщо у вас дуже велика робота з пам'яттю (читання джерела 1, читання джерела 2, швидке обчислення, запис), то більше тем не допоможе. Знову ж таки, це залежить від того, скільки даних ви читаєте / записуєте одночасно (тобто якщо ви використовуєте SSE 4.2 і читаєте значення 256 біт, що зупиняє всі потоки на їхньому кроці ... іншими словами, 1 потік, ймовірно, набагато простіше втілити в життя і Мабуть, майже настільки ж швидким, якщо насправді не швидшим. Це залежатиме від вашої архітектури процесів та пам'яті, деякі просунуті сервери управляють окремими діапазонами пам’яті для окремих ядер, тому окремі потоки стануть швидшими, припускаючи, що ваші дані належним чином подані ... ось чому, на деяких архітектури, 4 процеси будуть працювати швидше, ніж 1 процес з 4 потоками.)


4
Напевно, є й інші, але те, що я знаю, це процесор POWER від IBM. Вони мали системи з 4 або 8 потоками на процесор. Тепер вони можуть накручувати більше ядер, тому замість них пропонують 2 нитки на ядро ​​...
Alexis Wilke

Це старе, але більшість Intel i5, i7 має багатопотокові процесори, як, наприклад, у i7 cpu зазвичай 4 ядра, але 8 потоків.
Едгар.А

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

@TechnikEmpire Подивіться на цей intel.com/content/www/us/en/processors/core / ... , може бути , тоді ви можете зв'язатися з Інтел і зробити їх нитки теж.
g7k

24

Фактична ефективність залежатиме від того, наскільки добровільно вийде кожен потік. Наприклад, якщо потоки взагалі НЕ мають вводу / виводу і не використовують системних служб (тобто вони на 100% пов'язані з процесором), оптимальним є 1 потік на ядро. Якщо потоки роблять все, що вимагає очікування, тоді вам доведеться поекспериментувати, щоб визначити оптимальну кількість потоків. 4000 потоків мали б значне планування накладних витрат, тому, ймовірно, це теж не оптимально.


21

Відповідь залежить від складності алгоритмів, які використовуються в програмі. Я придумав метод обчислення оптимальної кількості ниток, зробивши два вимірювання часу обробки Tn і Tm для двох довільних кількості ниток 'n' і 'm'. Для лінійних алгоритмів оптимальною кількістю потоків буде N = sqrt ((m n (Tm * (n-1) - Tn * (m-1))) / (n Tn-m Tm)).

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


4
Чому це заборонено? Вибачте, але це найкраща відповідь на це питання. gonzalo звертається до жирної частини питання, а pkazen - у заголовку. Обидві відповіді дуже корисні, але відповідь pkazen є актуальною, оскільки у нас є систематичний метод наближення кількості потоку. Він навіть дає формулу алгоритмів ліній.
tobiak777

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

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

9

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

З Вікіпедії :

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

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

Якщо питання передбачає слабке масштабування, відповіді @ Гонсало достатньо. Однак якщо питання передбачає сильне масштабування, є ще щось додати. При сильному масштабуванні ви припускаєте фіксований розмір робочого навантаження, тому при збільшенні кількості потоків розмір даних, над якими потрібно працювати кожному потоку, зменшується. На сучасних процесорах доступ до пам’яті дорогий і бажано підтримувати локальність, зберігаючи дані в кешах. Отже, ймовірна оптимальна кількість потоків може бути знайдена, коли набір даних кожного потоку вміщується в кеш ядра кожного я (я не збираюся детально обговорювати, чи це кеш-пам'ять системи L1 / L2 / L3 системи).

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

Випадок 1: запустіть чотири нитки, де кожна нитка повинна заповнити 2AU. Кожен потік займає 10 секунд ( з великою кількістю пропусків кешу ). З чотирма ядрами загальна кількість часу становитиме 10 s (10s * 4 потоки / 4 ядра).

Випадок 2: запустіть з восьми ниток, де кожна нитка повинна заповнити 1AU. Кожен потік займає лише 2s (замість 5s через зменшену кількість пропусків кешу ). З чотирма ядрами загальна кількість часу складе 4s (2s * 8 потоків / 4 ядра).

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


7

4000 ниток за один раз досить великі.

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

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


7

Орієнтир.

Я б почав збільшувати кількість потоків для програми, починаючи з 1, а потім переходити до чогось типу 100, запускати три-п’ять випробувань для кожної кількості потоків і будувати собі графік швидкості роботи проти кількості потоків .

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

Ви не можете знати, поки не тестуєте.


3

Ви дізнаєтеся, скільки потоків можна запустити на вашій машині, виконавши команду htop або ps, яка повертає кількість процесу на вашій машині.

Ви можете використовувати man сторінку про команду 'ps'.

man ps

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

  1. ps -aux| wc -l
  2. ps -eLf | wc -l

Обчислення кількості користувальницького процесу:

  1. ps --User root | wc -l

Також ви можете використовувати "htop" [Довідник] :

Встановлення на Ubuntu або Debian:

sudo apt-get install htop

Встановлення на Redhat або CentOS:

yum install htop
dnf install htop      [On Fedora 22+ releases]

Якщо ви хочете скласти htop з вихідного коду, ви знайдете його тут .


2

Ідеал - 1 нитка на серцевину, поки жодна з ниток не блокується.

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


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

2
Що ж, ми маємо справу з магічним ідеально паралелізованим застосуванням. Якби я коли-небудь створив таку річ, я відчував би право зависати процесор стільки, скільки мені хочеться.
патрони

2

Одним із прикладів безлічі потоків ("пул потоків") по відношенню до одного на ядро ​​є використання веб-сервера в Linux або Windows.

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

У Windows сервер буде реалізований за допомогою портів завершення вводу-виводу - IOCP, що зробить подія програми: якщо введення / виведення завершиться, ОС запустить резервний потік для його обробки. Коли обробка завершена (як правило, з іншою операцією вводу-виводу, як у парі-відповіді на запит), потік повертається до порту (черги) IOCP, щоб чекати наступного завершення.

Якщо жодне введення-виведення не завершено, обробка не проводиться і жодна нитка не запускається.

Дійсно, Microsoft рекомендує не більше одного потоку на ядро ​​в реалізаціях IOCP. Будь-який I / O може бути приєднаний до механізму IOCP. МОК також може бути розміщений заявкою, якщо це необхідно.


Я не знаю, про який Linux ви говорите, але мої блоки, поки не з’явиться з'єднання. Я пропоную прочитати кілька речей про select () та FD_SET () та подібні функції / макроси.
Алексіс Вілке

Гаразд, так що немає асинхронної форми, яка повертається негайно?
Олоф Форшелл

З чоловічої сторінки select ():timeout is an upper bound on the amount of time elapsed before select() returns. If both fields of the timeval structure are zero, then select() returns immediately. (This is useful for polling.) If timeout is NULL (no timeout), select() can block indefinitely.
Alexis Wilke

0

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

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


0

Сподіваюся, це має сенс, Перевірте використання процесора та пам'яті та поставте деяке порогове значення. Якщо значення порогового значення перекреслено, не дозволяйте створювати новий потік ще дозволяти ...

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