Чому Node.js однопоточний? [зачинено]


255

У веб-серверах на базі PHP (або Java / ASP.NET / Ruby) кожен запит клієнта інстанціюється в новій темі. Але в Node.js всі клієнти працюють на одній нитці (вони можуть навіть використовувати однакові змінні!) Я розумію, що операції вводу / виводу є подіями, тому вони не блокують контур основного потоку.

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

Примітка. Я використовував кластеризацію, щоб обійти це, але це не дуже.


12
Нещодавно я подивився гарне відео (29 хвилин), що пояснює деякі теорії, що стоять за Node. Я навіть думаю, що хлопець розповідає про інтенсивні завдання CPU і коротко, як з ними впоратися: youtube.com/watch?v=L0pjVcIsU6A
— whirlwin

24
Ви можете це знати, але щоб бути зрозумілим, Node.js не є однопоточним. Ваш код JavaScript працює з однопотоковою передачею, але операції вводу-виводу та інші речі, які плагіни можуть робити, закінчуються з пулу потоків. Node.js дає велику користь багатопотоковому читанню, не маючи справи з багатопотоковим кодом. Також автори Node.js не обрали однопотоковий характер JavaScript, як це зробили автори JavaScript. Я не можу придумати спосіб, як JS міг би працювати в багатопотоковому контексті, але навіть якби вони були, V8 написаний не таким чином, який Node.js використовує в якості свого двигуна JavaScript.
— Бред

5
PHP є більш однопоточним, ніж JavaScript. Ви, напевно, думаєте про серверні модулі, такі як FastCGI або mod_php. Таким чином, ви насправді порівнюєте Node.js з Apache, Nginx або IIS - а не з PHP, Java або Ruby.
— Альваро Гонсалес

34
Вузол не є однопоточним. Це популярне оману. Навіть прості node -e 'setTimeout(()=>{},1000);' & ps -T h $! | wc -l; kill $!відображає п’ять потоків у моїй системі. Основний цикл подій є однопоточним (це не мало б сенсу, якби не було), але Node є багатопотоковим і ви можете писати багатопотокові однопроцесорні програми, якщо хочете. Я хотів би написати вичерпну відповідь про це, але деякі люди вирішили закрити ваше питання, тому я не можу. Я голосую за його повторне відкриття. Якщо вона отримає більше голосів і знову відкриється, будь ласка, згадайте мене в коментарі.
— rsp

2
@rsp дякую за ваш коментар, але я мав на увазі в основному потоці не пов'язані я / о. якщо ви робите щось, пов’язане з процесором, на зразок великого циклу, який щось робить, то сервер припиняє обробку з'єднань. тобто сервер на той час непридатний. тож нам залишається використовувати хаки, як кластери, просто для того, щоб зробити щось таке просте, замість того, щоб по суті протікати все з'єднання, як це робить більшість серверів. jxcore.com намагався вирішити це, але потім він використовує спеціальні / модифіковані плагіни вузла, що по суті робить його непридатним для мене.
— foreyez

Відповіді:


292

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

А ви знаєте що? На мій погляд, теорія підтверджена. Додаток node.js, який не займається процесором, може працювати на тисячі більше одночасних з'єднань, ніж Apache або IIS або інші потокові сервери.

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

Зрештою, я не думаю, що це в цілому краще чи гірше; це по-іншому, а іноді це краще, а іноді - ні. Використовуйте правильний інструмент для роботи.


26
Але веб-сервери, як правило, роблять АЛЬТЕ багато процесорних матеріалів, це НЕ ПРОСТО видобуток баз даних. Нам потрібно обробити те, що ми отримуємо, і багато ділової логіки робити багато часу, перш ніж подавати його клієнту.
— foreyez

22
Тож просто нерестові робітники, ну! Ось і вся угода з Node.js. Важкі речі можуть працювати в іншому процесі, і ви обробляєте його результати легким зворотним зв'язком.
— MaiaVictor

7
Проблема з цим полягає в тому, що на кожному робітнику працює процес рівня os. Ви побачите їх за допомогою команди "ps". Так що це потенційно означає тисячі процесів, що працюють на машині одночасно - це гайки!
— foreyez

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

15
Насправді, я хотів би @foreyez створити резервну копію цього твердження про те, що "веб-сервери, як правило, ALOT (sic) процесорних процесів". З мого досвіду, вони цього не роблять. А може, моє визначення поняття «інтенсивний процесор» відрізняється від його. Перетворення даних про продукти в інтерфейс не вимагає процесора, не обчислює замовлення тощо. Більша частина Інтернету є досить транзакційною. Інтенсивні матеріали процесора - це такі речі, як перетворення відео, перетворення форматів зображень тощо. Багато чого пояснюється введенням вводу файлів, який, власне, і вузол. І дозволяє легко завантажуватися на інший процес, який присвячений перетворенню.
— Пол

62

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

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

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

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

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


8
Node.js обмежений лише обробкою подіями через відсутність багатопотокової підтримки v8. Ну, а сама мова JavaScript не має необхідних функцій, тому будь-яке впровадження в кінцевому підсумку виявиться складним. Це головний винуватець Node.js, на мою думку. На інших мовах ви можете вибрати те, що вам потрібно. Або якийсь гібрид обох моделей, наприклад, java NIO.
— FrameGrace

2
@Kazaag, Сучасні веб - сервери роблять підтримувати ThreadPool. Вони не просто нерозумно породжують нову нитку за завантаження сторінки. Це більш старі веб-сервери.
— Pacerier

1
@Pacerier Я ніколи не говорив про те, що нова потік нереститься, але кожен потік виділяється на один запит до завершення запиту.
— Казааг

2
@Kazaag Однозначно не є загальним правилом, що "кожен потік призначається одному запиту до завершення запиту". Тобто в .Net (включаючи обробку HTTP-запитів) можна і потрібно використовувати програмування async (на основі завдань), і це випустить потоки під час очікування завершення вводу / виводу та інших операцій з асинхронізацією. Це стосується і програмування високого рівня, тобто контролерів MVC / API. Тож на практиці може бути 20 запитів HTTP, які очікують на розгляд, але лише один активний потік.
— користувач3285954

29

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

В один момент (0.7) автори намагалися ввести ізоляти як спосіб здійснення декількох обчислень, але в кінцевому підсумку були видалені: https://groups.google.com/forum/#!msg/nodejs/zLzuo292hX0/F7gqfUiKi2sJ


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