Багатопоточність: В чому сенс більше ниток, ніж ядер?


142

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


52
нам подобається такий тип запитань, вони ставлять під сумнів саме те, що є принциповим, що вважається цілком зрозумілим. Продовжуємо ..
Шрінівас Редді Татіпарті

6
Коли останній раз на вашому чотирьохядерному комп'ютері одночасно працювали Firefox, MS Word, Winamp, Eclipse та менеджер завантажень (більше чотирьох програм / процесів)? Крім того, одна програма іноді може породити більше чотирьох потоків - як щодо цього?
Amarghosh

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

1
@Amarghosh Я думаю, що це було питання, чому одна програма може захотіти породити більше ниток, ніж ядер, якщо це, здається, не приносить користі продуктивності. І ваш приклад з більш ніж чотирма програмами тут не зовсім актуальний. Як ви правильно зазначали, це процеси. Функція багатозадачності ОС (процес мультиплексування) має дуже мало спільного з потоками в межах одного процесу.
Олександр Іваніков

Відповіді:


81

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

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

Це насправді складніше, ніж це:

  • Що робити, якщо у вас є п’ять розрядів роботи, які потрібно виконати відразу? Більше сенсу запустити їх усі одразу, ніж запустити їх чотири, а потім запустити п'яту.

  • Рідко для потоку справді потрібен 100% процесор. Наприклад, в момент використання дискового або мережевого вводу-виводу, можливо, потенційно витратити час на очікування, не роблячи нічого корисного. Це дуже поширена ситуація.

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

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


16
+1 для ", але тільки якщо для кожного окремого потоку потрібно 100% процесора". Це було припущення, яке я не розумів, що я роблю.
Нік Хайнер

1
Чудова відповідь на чудове запитання. Дякую!
Край

53

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

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


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

26

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

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

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

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


1
Це цікава думка ... Я завжди чув, що багатопотокове додаток є чистим доповненням складності, але те, що ви говорите, має сенс.
Нік Хайнер

Багатопотокове додаток додає складності, якщо його проблеми недостатньо розділені. Якщо він розроблений з мінімальним перекриттям проблем (і, таким чином, загальним станом), це чисте заощадження в питаннях складності.
ДАЙТЕ МОЕ правильне ДУМКУ

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

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

15

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

Розглянемо нитку, якій потрібно зчитувати дані з жорсткого диска. У 2014 році типове ядро ​​процесора працює на частоті 2,5 ГГц і може виконувати 4 інструкції за цикл. З часом циклу 0,4 нс процесор може виконувати 10 інструкцій за наносекунд. Якщо типовий час механічного жорсткого диска становить близько 10 мілісекунд, процесор здатний виконати 100 мільйонів інструкцій за час, необхідний для зчитування значення з жорсткого диска. Можуть бути значні поліпшення продуктивності на жорстких дисках з невеликим кешем (4 МБ буфера) та гібридних накопичувачах з кількома ГБ пам’яті, оскільки затримка даних для послідовного читання або зчитування з гібридного розділу може бути на кілька порядків швидшою.

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

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

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

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

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


те ж саме можна зробити з однією ниткою та чергою, хоча: \ чи справді є користь мати 80 ниток на 2-4 ядрах, над тим, що у вас є лише 2-4 ядра, які просто з'їдають завдання з черги, як тільки вони прибувають і їм нема чого робити?
Дмитро

8

Більшість відповідей вище стосуються продуктивності та одночасної роботи. Я збираюся підійти до цього з іншого кута.

Візьмемо випадок, скажімо, спрощеної програми емуляції терміналу. Ви повинні виконати такі дії:

  • стежте за вхідними символами з віддаленої системи та показуйте їх
  • стежте за предметами, які надходять з клавіатури, і надсилайте їх у віддалену систему

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

Тепер цикл для читання з віддаленого просто, відповідно до наступного псевдокоду:

while get-character-from-remote:
    print-to-screen character

Цикл моніторингу клавіатури та надсилання також простий:

while get-character-from-keyboard:
    send-to-remote character

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

loop:
    check-for-remote-character
    if remote-character-is-ready:
        print-to-screen character
    check-for-keyboard-entry
    if keyboard-is-ready:
        send-to-remote character

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

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

То чому б ви не використовували різьблення?

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

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


6

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

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

Також дивіться це пов’язане питання: Практичне використання для потоків


Обробка користувальницького інтерфейсу - це класичний приклад завдання, пов'язаного з IO. Непогано мати одне ядро ​​CPU, яке виконує як обробку, так і завдання IO.
Стипендіати Доналу

6

Я категорично не згоден із твердженням @ kyoryu, що ідеальне число - це один потік на процесор.

Подумайте про це так: чому ми маємо багатообробні операційні системи? Більшість комп'ютерних історій майже всі комп'ютери мали один процесор. Ще з 1960-х років усі "справжні" комп'ютери мали багатопроцесорні (також багатозадачні) операційні системи.

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

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

Нитки - це лише завдання, які трохи ефективніші. Немає принципової різниці між завданням, процесом та потоком.

Процесор - це страшна річ, тому готові використовувати багато речей, коли можна.

Я погоджусь, що для більшості процедурних мов, C, C ++, Java тощо, написання належного безпечного коду для потоків - це велика робота. Сьогодні на ринку є 6 основних процесорів, а 16 основних процесорів недалеко, я очікую, що люди відійдуть від цих старих мов, оскільки багатопотоковість стає все більш важливою вимогою.

Незгода з @kyoryu - це лише ІМХО, інше - факт.


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

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

За винятком складання білка, SETI тощо, немає практичних завдань користувача, які обчислюються дуже довго. Завжди є необхідність отримати інформацію від користувача, поговорити на диску, поговорити з СУБД тощо. Так, витрата fork () - одна з багатьох речей, за які Cutler проклинав NT з тим, що знали інші в DEC.
fishtoprecords

5

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

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


2
Ви пишете програмне забезпечення для операційної системи, яка підтримує нитку, але не має можливості для мультиплексування io? Я думаю, що веб-сервер - це, мабуть, поганий приклад, оскільки в цьому випадку мультиплексування io майже завжди буде більш ефективним, ніж нерестування більшої кількості потоків, ніж ядер.
Джейсон Коко

3

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


Точно. просто скористайтеся диспетчером завдань у Windows або TOP у реальній ОС, і подивіться, скільки завдань / процесів є глибокими. Його завжди 90% або більше.
fishtoprecords

2

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


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

2

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

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

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

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


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

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

1

Ідеальне використання ниток - це дійсно одне на ядро.

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

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


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

@ Nick Bastin: Так, але ефективніше вставляти ці завдання в чергу завдань і виконувати їх із цієї черги (або подібної стратегії). Для оптимальної ефективності 1 потік на ядро ​​перемагає всіх, оскільки це запобігає непотрібному переключенню контексту та виділенню додаткових стеків. Незважаючи ні на що, періодичне завдання повинне вкрасти ядро ​​під час "активного", оскільки процесор може фактично виконувати лише одне завдання на ядро ​​(плюс такі речі, як гіперточення, якщо вони доступні).
kyoryu

@ Нік Бастін: На ​​жаль, як я вже говорив у головній відповіді, більшість сучасних мов не піддаються легкому впровадженню системи, яка робить це ефективно, а не дрібницею - ви в кінцевому підсумку ведете якусь боротьбу з типовим використанням мови.
кьорю

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

@Nick Bastin: Отже, підсумовуючи, одна нитка на ядро ​​є ідеальною, але насправді досягти цього не дуже ймовірно. Я, мабуть, мав бути сильнішим, ніж «дещо важким», коли говорив про те, наскільки ймовірно реально досягти такого.
kyoryu

1

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

Зазвичай це не є великою проблемою (якщо це проблема, ОС або API повинні постачатися з альтернативним асинхронним режимом роботи, тобто:) select(2), оскільки це, ймовірно, означає, що нитка буде спати під час очікування I / O завершення. З іншого боку, якщо щось робить важкі обчислення, вам доведеться помістити його в окрему нитку, ніж, скажімо, нитку GUI (якщо ви не любите мультиплексування вручну).


1

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

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


0

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

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

У відповідь на ваше друге запитання: більшість процесів / потоків не пов'язані з процесором (тобто не працюють постійно і безперебійно), а натомість зупиняються і чекають часто, коли введення-виведення закінчиться. Під час цього очікування інші процеси / потоки можуть працювати без "крадіжки" з коду очікування (навіть на одній основній машині).


-5

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


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

-8

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

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

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


7
Не (цілком!) Вартістю -1, але серйозно, це стосується найдурішого чудового, що я чув, як хтось говорив на цю тему. У мене, наприклад, немає проблем із впровадженням державної машини. Взагалі жодної. Мені просто не подобається користуватися ними, коли є інші інструменти, які залишають після себе чіткіший і простіший в обслуговуванні код. Державні машини мають свої місця, і в тих місцях вони не можуть відповідати. Переплетення CPU-інтенсивних операцій з оновленнями графічного інтерфейсу не одне з таких місць. Принаймні, супроводи - це кращий вибір, а різьблення - ще краще.
ДАЙТЕ МОЕ правильне ДУМКА

Для кожного, хто моментує свою відповідь, це НЕ аргумент проти використання ниток! Якщо ви можете кодувати державну машину, яка чудова, і ви впевнені, що часто має сенс запускати станкові машини в окремих потоках, навіть якщо цього не потрібно. Моя зауваження полягала в тому, що часто вибір потоків здійснюється в основному з бажання уникати проектування державних машин, які багато програмістів вважають "занадто жорсткими", а не для будь-якої іншої вигоди.
R .. GitHub СТОП ДОПОМОГАЙТЕ
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.