Почему Node.js однопоточный? [закрыто]


256

В веб-серверах на основе PHP (или Java / ASP.NET / Ruby) каждый клиентский запрос создается в новом потоке. Но в Node.js все клиенты работают в одном потоке (они могут даже использовать одни и те же переменные!) Я понимаю, что операции ввода-вывода основаны на событиях, поэтому они не блокируют цикл основного потока.

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

Примечание: я использовал кластеризацию, чтобы обойти это, но это не красиво.


12
Недавно я посмотрел хорошее видео (29 минут), объясняющее некоторые из теорий, стоящих за Node. Я даже думаю, что этот парень говорит о задачах, интенсивно использующих процессор, и кратко о том, как их решать: 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 спасибо за ваш комментарий, но я имел в виду в основной теме, не связанной с вводом / выводом. если вы делаете что-то, связанное с процессором, например большой цикл for, который что-то делает, то сервер останавливает обработку соединений. это означает, что сервер не работает в данный момент. поэтому мы оставляем использование хаков типа кластеров просто для того, чтобы сделать что-то настолько простое, а не по своей сути потоковое каждое соединение, как это делают большинство серверов. jxcore.com попытался решить эту проблему, но затем он использует специальные / модифицированные плагины для узлов, что, по сути, делает его непригодным для меня.
foreyez

Ответы:


292

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

И знаешь, что? По моему мнению, эта теория была подтверждена. Приложение node.js, которое не выполняет нагрузку на процессор, может запускать на тысячи параллельных соединений больше, чем Apache, IIS или другие серверы на основе потоков.

Однопоточная, асинхронная природа усложняет ситуацию. Но вы честно думаете, что это сложнее, чем многопоточность? Одно состояние гонки может испортить весь ваш месяц! Или очистите пул потоков из-за каких-то настроек и наблюдайте, как время отклика замедляется до сканирования! Не говоря уже о взаимоблокировках, инверсиях приоритетов и всех других движениях, связанных с многопоточностью.

В конце концов, я не думаю, что это повсеместно лучше или хуже; это отличается, а иногда лучше, а иногда нет. Используйте правильный инструмент для работы.


26
Но веб-серверы, как правило, делают ОЧЕНЬ интенсивное использование ресурсов процессора, это не просто выборка базы данных. Нам нужно обрабатывать то, что мы получаем, и много времени делать бизнес-логикой, прежде чем передать это клиенту.
foreyez

22
Так что просто рабочие икры, хорошо! Вот и вся сделка с Node.js. Тяжелые вещи могут выполняться в другом процессе, и вы обрабатываете его, что приводит к облегченному обратному вызову.
MaiaVictor

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

9
@foreyez, вам не нужен процесс для каждого пользователя. У вас есть выбор в том, как вы распределили нагрузку. Кроме того, не каждый делает тонну ресурсоемких вещей. Узел - это инструмент для работы ... может быть, не ваша работа, а множество видов работ.
Брэд

15
На самом деле, я бы хотел, чтобы @foreyez подтвердил это утверждение о том, что «веб-серверы обычно ALOT (sic) из ресурсоемких ресурсов». По моему опыту, они этого не делают. Или, может быть, мое определение «интенсивного использования процессора» отличается от его. Преобразование данных о продукте в пользовательский интерфейс не требует интенсивной загрузки ЦП, а также расчета заказов и т. П. Большая часть Интернета довольно транзакционна. Интенсивная загрузка процессора - это такие вещи, как преобразование видео, преобразование форматов изображений и т. Д. Многое из этого связано с файловым вводом / выводом, который, на самом деле, довольно хорошо работает с узлом. И позволяет легко перенести в другой процесс, посвященный конвертации.
Пол

63

Проблема с моделью «один поток на запрос» для сервера заключается в том, что они не хорошо масштабируются для нескольких сценариев по сравнению с моделью потока цикла событий.

Как правило, в сценариях с интенсивным вводом / выводом запросы проводят большую часть времени в ожидании завершения ввода / вывода. В течение этого времени в модели «один поток на запрос» ресурсы, связанные с потоком (например, память), не используются, а память является ограничивающим фактором. В модели цикла событий поток цикла выбирает следующее событие (ввод / вывод завершен) для обработки. Таким образом, поток всегда занят (если вы, конечно, программируете его правильно).

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

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

Если вы ищете серебряную пулю, которая подойдет к любому сценарию без каких-либо усилий, вы получите пулю в ногу.


8
Node.js ограничен обработкой только событий из-за отсутствия поддержки многопоточности v8. Ну, самому языку javascript не хватает необходимых функций, поэтому любая реализация будет непростой. Это главный виновник Node.js, на мой взгляд. На других языках вы можете выбрать то, что вы хотите. Или какой-то гибрид обеих моделей, например Java NIO.
FrameGrace

2
@Kazaag, Современные веб - серверы делают поддерживать ThreadPool. Они не просто тупо порождают новый поток на загрузку страницы. Это старые веб-серверы.
Pacerier

1
@Pacerier Я никогда не говорил, что новый поток является порожденным, но каждый поток выделяется для одного запроса, пока запрос не будет завершен.
Казааг

2
@ Kazaag Это определенно не общее правило, что «каждый поток выделяется на один запрос, пока запрос не будет завершен». Т.е. в .Net (включая обработку HTTP-запросов) можно и нужно использовать асинхронное (на основе задач) программирование, и это освободит потоки в ожидании завершения ввода-вывода и других асинхронных операций. Это применимо и к высокоуровневому программированию, то есть к контроллерам MVC / API. Таким образом, на практике может быть ожидающих 20 HTTP-запросов, но только один активный поток.
user3285954

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.