Как Node.js обрабатывает входящие запросы?

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

Насколько мне известно, Node.js полагается на шаблон реактора для обработки каждого входящего запроса. Этот алгоритм основан на алгоритме Демультиплексор событий. Второй отвечает за обработку операции запроса и ее ресурсов, а затем, когда операция завершена, он добавляет «результат» в Очередь событий. После этого Цикл событий теперь отвечает за выполнение обработчиков для каждого события.

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

Я нашел это в документации Node.js:

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

Означает ли это, что задачи демультиплексора событий не обрабатываются узлом и что узел просто получает результат, чтобы добавить его в очередь событий? Разве это не означает, что Node не является однопоточным?

Я нашел в Интернете несколько полезных рисунков, которые четко объясняют путь, по которому следует каждый запрос, но очень трудно найти что-то, объясняющее фактическое время, в течение которого поток обрабатывает каждый запрос.


person Luis Orbaiceta    schedule 16.09.2020    source источник
comment
Обычно на каждый контекст выполнения приходится один цикл обработки событий. Чтобы использовать несколько ядер ЦП, модуль cluster используется для разветвления дополнительных циклов обработки. . Кроме того, узел является однопоточным в пользовательском коде. Всякий раз, когда вы вызываете библиотечную функцию, ее внутренности могут делать что угодно, даже порождать потоки, пока результат возвращается в цикл обработки событий, который обрабатывается вашим пользовательским кодом в однопоточном режиме.   -  person Wiktor Zychla    schedule 16.09.2020
comment
Я нашел это выступление действительно полезным на случай, если кому-то будет интересно youtu.be/zphcsoSJMvM   -  person Luis Orbaiceta    schedule 19.09.2020


Ответы (1)


В node.js он запускает ваш Javascript в одном потоке (при условии, что мы не говорим о рабочих потоках или кластеризации). Но многие асинхронные операции во встроенной библиотеке node.js, такие как файловый ввод-вывод или некоторые криптографические операции, используют собственные потоки для выполнения своей задачи. Таким образом, когда вы вызываете асинхронные операции, такие как fs.open(), для открытия файла, он переходит к собственному коду, захватывает поток из внутреннего пула потоков, и этот поток начинает открывать файл. Затем функция fs.open() возвращается к вашему Javascript (пока поток продолжается в фоновом режиме). Некоторое время спустя, когда он завершает свою задачу, внутренний поток вставляет событие в очередь событий nodejs, и когда у nodejs есть циклы для проверки очереди событий, он находит это событие и запускает обратный вызов Javascript, связанный с ним, чтобы предоставить асинхронный результат обратно в ваш Javascript.

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

Таким образом, nodejs использует потоки собственного кода для некоторых внутренних операций с собственным кодом. Другие вещи, такие как работа в сети и таймеры, реализованы без потоков.

Затем, если я отправлю запрос на получение данных из базы данных в Node, как его обработает демультиплексор событий? Останавливает ли основной поток цикл событий для обработки этой операции, а затем возобновляет работу после того, как обработчик событий поставлен в очередь?

Такие термины, как демультиплексор событий, применяются к node.js. Они вообще не используются в node.js, поэтому я не совсем уверен, о чем вы спрашиваете.

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

Когда входящий запрос Fetch (который является просто входящим http-запросом) поступает на сервер, ОС сначала ставит его в очередь. Затем, когда цикл событий имеет возможность его увидеть, он добавляется в очередь событий node.js и обслуживается в порядке FIFO, когда другие события, которые были до него, обрабатываются. Теперь цикл событий nodejs не так прост, как одна очередь событий. На самом деле у него есть несколько разных очередей для разных типов работы и есть приоритеты для того, что запускается первым, но на самом простом уровне вы можете начать думать об этом как об одной очереди FIFO. И ничего никогда не прерывается.

Извлеките событие из очереди событий, запустите связанный с ним обратный вызов Javascript. Когда этот обратный вызов вернется обратно в цикл событий, получите следующее событие и сделайте то же самое.

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

person jfriend00    schedule 16.09.2020
comment
Затем, если я отправлю запрос на получение данных из базы данных в Node, как его обработает демультиплексор событий? Останавливает ли основной поток цикл событий для обработки этой операции, а затем возобновляет работу после того, как обработчик событий поставлен в очередь? - person Luis Orbaiceta; 16.09.2020
comment
@LuisOrbaiceta - посмотрите, что я добавил к своему ответу. Было бы лучше, если бы вы использовали термины, которые nodejs использует для описания себя, а не свои собственные термины, поскольку остальные из нас действительно не знают точно, что означают ваши собственные термины (например, демультиплексор событий) в этом контексте, поскольку это не термин nodejs . - person jfriend00; 16.09.2020
comment
Я читал об этом термине в объяснении шаблона реактора, которое Марио Кашаро дает в своей книге «Шаблоны проектирования Node.Js» miro.medium.com/max/1582/1*MABVZQvtz5jkv4Fh23kzRg.png - person Luis Orbaiceta; 16.09.2020
comment
@LuisOrbaiceta - Ну, я никогда не слышал, чтобы в node.js назывался мультиплексор событий, так что, по-видимому, этот термин применил автор этой статьи. Я не уверен, откуда эта статья взяла это. Существует несколько очередей событий (для разных типов событий) и цикл событий, который циклически проходит через разные очереди в определенном порядке и с определенными приоритетами, определяя, какое ожидающее событие в очереди обрабатывать следующим. - person jfriend00; 16.09.2020
comment
Но, насколько я понимаю, наиболее важным строительным блоком Node является Libuv, построенный на основе шаблона реактора, который имеет синхронный демультиплексор событий для обработки всех неблокирующих системных операций ввода-вывода. - person Luis Orbaiceta; 17.09.2020