Как работают Node.js потоки?

У меня вопрос о потоках Node.js - в частности, как они работают концептуально.

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

Мое ограниченное понимание веб-коммуникации, HTTP, заключается в том, что полные "пакеты" данных отправляются туда и обратно. Подобно индивидуальному заказу каталога компании, клиент отправляет на сервер запрос GET (каталог), и сервер отвечает каталогом. Браузер не получает страницу каталога, а всю книгу.

Являются ли node потоками, возможно, многочастными сообщениями?

Мне нравится модель REST - особенно, что она без гражданства. Каждое отдельное взаимодействие между браузером и сервером полностью самодостаточно и достаточно. Потоки node поэтому не RESTful? Один разработчик упомянул сходство с сокетными трубами, которые поддерживают соединение открытым. Вернемся к примеру заказа каталога, это будет как рекламный ролик с линией "Но подождите! Там еще!" вместо полного каталога?

Большая часть потоков - это возможность для "нисходящего потока" получателя отправлять сообщения типа "пауза" и "продолжить" вверх по потоку. В чем состоят эти сообщения? Это POST?

Наконец, мое ограниченное визуальное представление о том, как работает node, включает этот цикл событий. Функции могут быть размещены на отдельных потоках из пула потоков, и цикл событий продолжается. Но не следует ли передавать поток данных, чтобы цикл цикла был занят (т.е. Остановлен), пока поток не будет завершен? Как он также следит за запросом "паузы" из нисходящего потока? N Проводит ли цикл событий поток из другого потока из пула и когда он встречает запрос "пауза", извлекает соответствующий поток и приостанавливает его?

Я прочитал документы Node.js, завершил учебники по учебникам узлов, построил приложение heroku, купил две книги (реальные, автономные, книги, похожие на каталоги, которые раньше говорили и, вероятно, не понравились потокам node), попросил нескольких инструкторов "node" на кодах bootcamps - все говорят о том, как использовать потоки, но никто не говорит о том, что на самом деле происходит ниже.

Возможно, вы столкнулись с хорошим ресурсом, объясняющим, как это работает? Возможно, хорошая антропоморфная аналогия для не-CS-ума?

Ответ 1

Первое, что нужно отметить: потоки node.js не ограничены HTTP-запросами. HTTP-запросы/Сетевые ресурсы - всего лишь один пример потока в node.js.

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

Скажем, что у вас есть файл (несколько гигабайт) и вы хотите преобразовать все строчные буквы в верхние регистры и записать результат в другой файл. Наивный подход прочитал бы весь файл, используя fs.readFile (обработка ошибок опущена для краткости):

fs.readFile('my_huge_file', function (err, data) {
    var convertedData = data.toString().toUpperCase();

    fs.writeFile('my_converted_file', convertedData);
});

К сожалению, этот подход будет легко перегружать вашу оперативную память, так как весь файл должен быть сохранен перед его обработкой. Вы также тратите драгоценное время на ожидание чтения файла. Не имеет смысла обрабатывать файл в небольших кусках? Вы можете начать обработку, как только вы получите первые байты, ожидая, пока жесткий диск предоставит оставшиеся данные:

var readStream = fs.createReadStream('my_huge_file');
var writeStream = fs.createWriteStream('my_converted_file');
readStream.on('data', function (chunk) {
    var convertedChunk = chunk.toString().toUpperCase();
    writeStream.write(convertedChunk);
});
readStream.on('end', function () {
    writeStream.end();
});

Этот подход намного лучше:

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

Как только вы откроете поток node.js откроет файл и начнет читать с него. Как только операционная система передает некоторые байты в поток, который считывает файл, он будет передан вместе с вашим приложением.


Возвращаясь к потокам HTTP:

  • Здесь также актуальна первая проблема. Возможно, злоумышленник отправляет вам большое количество данных, чтобы перегрузить вашу RAM и удалить (DoS) вашу службу.
  • Однако второй вопрос еще более важен в этом случае: Сеть может быть очень медленной (думаю, смартфоны), и это может занять много времени, пока все будет отправлено клиентом. Используя поток, вы можете начать обработку запроса и сократить время отклика.

При приостановке HTTP-потока: это не выполняется на уровне HTTP, но ниже. Если вы приостановите поток node.js, просто прекратите чтение из основного сокета TCP. То, что происходит тогда, зависит от ядра. Он все равно может буферизовать входящие данные, поэтому он готов для вас, как только вы закончите свою текущую работу. Он также может сообщить отправителю на уровне TCP, что он должен приостановить отправку данных. Приложениям не нужно иметь дело с этим. Это не их дело. На самом деле приложение-отправитель, вероятно, даже не понимает, что вы больше не активно читаете!

Таким образом, это в основном о предоставлении данных, как только оно доступно, но без подавления ваших ресурсов. Основная трудная работа выполняется либо операционной системой (например, net, fs, http), либо автором используемого вами потока (например, zlib, который является потоком Transform и обычно закреплен болтами на fs или net).

Ответ 2

Я думаю, вы слишком задумываетесь, как все это работает, и мне это нравится.

Какие потоки хороши для

Потоки хороши для двух вещей:

  • когда операция медленная, и она может дать вам частичные результаты по мере их получения. Например, прочитайте файл, он медленный, потому что жесткие диски медленны, и он может дать вам часть файла по мере его чтения. С потоками вы можете использовать эти части файла и сразу же начать их обрабатывать.

  • они также хорошо связывают программы вместе (функции чтения). Так же, как и в командной строке, вы можете комбинировать разные программы для получения желаемого результата. Пример: cat file | grep word.

Как они работают под капотом...

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

Чтобы понять ваш пример http, вам нужно понять, как работает http

Существуют различные кодировки, которые может отправлять веб-страница. В начале был только один способ. Когда вся страница была отправлена, когда она была запрошена. Теперь для этого есть более эффективные кодировки. Один из них фрагментируется, когда части веб-страницы отправляются до отправки всей страницы. Это хорошо, потому что веб-страницу может обрабатываться по мере ее получения. Представьте себе веб-браузер. Он может начать рендеринг веб-сайтов до завершения загрузки.

Ваши вопросы .pause и. Continue

Во-первых, потоки Node.js работают только в той же программе Node.js. Потоки Node.js не могут взаимодействовать с потоком на другом сервере или даже в программе.

Это означает, что в приведенном ниже примере Node.js не может разговаривать с веб-сервером. Он не может сказать, чтобы он приостанавливался или возобновлялся.

Node.js <-> Network <-> Webserver

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

Итак, что на самом деле происходит, когда вы делаете в Node.js.pause или .continue?

Он начинает буферизовать запрос до тех пор, пока вы не начнете его снова использовать. Но загрузка никогда не прекращалась.

Цикл событий

У меня есть целый ответ, чтобы объяснить, как работает Event Loop, но я думаю, что вам лучше смотреть этот разговор.

Ответ 3

Нижеприведенный график представляется довольно точным обзором/диаграммой 10.000 футов для класса потоков node.

Он представляет streams3, внесенный Крис Дикинсон.

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