Итак, у меня есть понимание того, как работает Node.js: у него есть единственный поток слушателя, который получает событие, а затем делегирует его рабочему пулу. Рабочий поток уведомляет слушателя после завершения работы, а затем слушатель возвращает ответ вызывающей стороне.
Мой вопрос таков: если я включаю HTTP-сервер в Node.js и вызываю sleep для одного из событий маршрутизации (например, «/ test / sleep»), вся система останавливается. Даже один поток слушателя. Но я понял, что этот код происходит в рабочем пуле.
Теперь же, когда я использую Mongoose для общения с MongoDB, чтение из БД - дорогостоящая операция ввода-вывода. Кажется, что Node может делегировать работу потоку и получить обратный вызов по завершении; время, затраченное на загрузку из БД, похоже, не блокирует систему.
Как Node.js решает использовать поток пула потоков вместо потока слушателя? Почему я не могу написать код события, который спит и блокирует только поток пула потоков?
Ответы:
Ваше понимание того, как работает узел, неверно ... но это распространенное заблуждение, потому что реальность ситуации на самом деле довольно сложна и обычно сводится к лаконичным маленьким фразам вроде «узел однопоточный», которые чрезмерно упрощают вещи .
На данный момент мы проигнорируем явную многопроцессорность / многопоточность через кластер и потоки webworker и просто поговорим о типичном непоточном узле.
Узел работает в одном цикле событий. Он однопоточный, и вы всегда получаете только этот один поток. Весь написанный вами javascript выполняется в этом цикле, и если в этом коде происходит операция блокировки, то он блокирует весь цикл, и больше ничего не произойдет, пока он не завершится. Это типичная однопоточная природа узла, о которой вы так много слышите. Но это еще не вся картина.
Некоторые функции и модули, обычно написанные на C / C ++, поддерживают асинхронный ввод-вывод. Когда вы вызываете эти функции и методы, они внутренне управляют передачей вызова рабочему потоку. Например, когда вы используете
fs
модуль для запроса файла,fs
модуль передает этот вызов рабочему потоку, и этот рабочий ждет своего ответа, который затем отправляет обратно в цикл событий, который продолжался без него в тем временем. Все это абстрагируется от вас, разработчика узла, а некоторая часть абстрагируется от разработчиков модулей с помощью libuv .Как указал Денис Доллфус в комментариях (из этого ответа на аналогичный вопрос), стратегия, используемая libuv для достижения асинхронного ввода-вывода, не всегда является пулом потоков, в частности, в случае
http
модуля, другая стратегия кажется используется в это время. Для наших целей здесь в основном важно отметить, как достигается асинхронный контекст (с помощью libuv) и что пул потоков, поддерживаемый libuv, является одной из нескольких стратегий, предлагаемых этой библиотекой для достижения асинхронности.В этой отличной статье, по большей части связанной касательной, есть гораздо более глубокий анализ того, как узел достигает асинхронности, а также некоторые связанные с этим потенциальные проблемы и способы их решения . Большинство из них расширяет то, что я написал выше, но дополнительно указывает:
UV_THREADPOOL_SIZE
переменной среды, если вы делаете это до того, как пул потоков потребуется и будет создан:process.env.UV_THREADPOOL_SIZE = 10;
Если вам нужна традиционная многопроцессорная обработка или многопоточность в узле, вы можете получить это через встроенный
cluster
модуль или различные другие модули, такие как вышеупомянутыеwebworker-threads
, или вы можете подделать его, реализовав какой-либо способ разбивки своей работы и вручную используяsetTimeout
илиsetImmediate
илиprocess.nextTick
приостановить вашу работу и продолжить ее в более позднем цикле, чтобы позволить другим процессам завершиться (но это не рекомендуется).Обратите внимание: если вы пишете долго работающий / блокирующий код на javascript, вы, вероятно, ошибаетесь. Другие языки будут работать намного эффективнее.
источник
Это не совсем так. Node.js имеет только один «рабочий» поток, который выполняет javascript. Внутри узла есть потоки, которые обрабатывают обработку ввода-вывода, но думать о них как о «рабочих» - неправильное представление. На самом деле есть просто обработка ввода-вывода и несколько других деталей внутренней реализации узла, но как программист вы не можете влиять на их поведение, кроме нескольких разных параметров, таких как MAX_LISTENERS.
В JavaScript нет механизма сна. Мы могли бы обсудить это более конкретно, если бы вы опубликовали фрагмент кода, который, по вашему мнению, означает «сон». Нет такой функции, которую можно было бы вызвать, например, для имитации чего-то вроде
time.sleep(30)
Python. Там же ,setTimeout
но это в корне не сон.setTimeout
иsetInterval
явно освобождает , а не блокирует, цикл событий, чтобы другие части кода могли выполняться в основном потоке выполнения. Единственное, что вы можете сделать, - это зациклить CPU с вычислениями в памяти, что действительно приведет к голоданию основного потока выполнения и сделает вашу программу невосприимчивой.Сетевой ввод-вывод всегда асинхронный. Конец истории. Disk IO имеет как синхронные, так и асинхронные API, поэтому «решения» нет. node.js будет вести себя в соответствии с основными функциями API, которые вы вызываете синхронизацией по сравнению с обычным асинхронным. Например:
fs.readFile
противfs.readFileSync
. Для дочерних процессов, существуют также отдельныеchild_process.exec
иchild_process.execSync
API - интерфейсы.Практическое правило - всегда использовать асинхронные API. Веские причины для использования API синхронизации - это код инициализации в сетевой службе до того, как она будет прослушивать соединения, или простые сценарии, которые не принимают сетевые запросы для инструментов сборки и тому подобное.
источник
fs
, насколько мне известно,Пул потоков, как когда и кто использовал:
Во-первых, когда мы используем / устанавливаем Node на компьютер, он запускает процесс среди других процессов, который называется процессом узла на компьютере, и продолжает работать, пока вы его не убьете. И этот запущенный процесс - это наш так называемый одиночный поток.
Таким образом, механизм однопоточности позволяет легко заблокировать приложение узла, но это одна из уникальных функций, которые Node.js привносит в таблицу. Итак, опять же, если вы запустите приложение узла, оно будет работать только в одном потоке. Независимо от того, есть ли у вас 1 или миллион пользователей, одновременно обращающихся к вашему приложению.
Итак, давайте точно поймем, что происходит в единственном потоке nodejs, когда вы запускаете свое приложение node. Сначала инициализируется программа, затем выполняется весь код верхнего уровня, что означает все коды, которые не находятся внутри какой-либо функции обратного вызова ( помните, что все коды внутри всех функций обратного вызова будут выполняться в цикле событий ).
После этого выполняется весь код модулей, затем регистрируются все обратные вызовы, и, наконец, запускается цикл обработки событий для вашего приложения.
Итак, как мы обсуждали ранее, все функции обратного вызова и коды внутри этих функций будут выполняться в цикле событий. В цикле событий нагрузки распределяются по разным фазам. В любом случае, я не собираюсь здесь обсуждать цикл событий.
Что ж, для лучшего понимания пула потоков я прошу вас представить, что в цикле событий коды внутри одной функции обратного вызова выполняются после завершения выполнения кодов внутри другой функции обратного вызова, теперь, если есть некоторые задачи, на самом деле слишком тяжелые. Затем они заблокировали бы наш единственный поток nodejs. Итак, здесь появляется пул потоков, который, как и цикл событий, предоставляется Node.js библиотекой libuv.
Таким образом, пул потоков не является частью самого nodejs, он предоставляется libuv для переноса тяжелых задач на libuv, и libuv будет выполнять эти коды в своих собственных потоках, а после выполнения libuv вернет результаты событию в цикле событий.
Пул потоков дает нам четыре дополнительных потока, которые полностью отделены от основного потока. И мы действительно можем настроить его до 128 потоков.
Таким образом, все эти потоки вместе образуют пул потоков. а затем цикл обработки событий может автоматически выгружать тяжелые задачи в пул потоков.
Самое интересное, что все это происходит автоматически за кулисами. Не мы, разработчики, решаем, что будет попадать в пул потоков, а что нет.
В пул потоков поступает много задач, например
источник
Это недоразумение - просто разница между упреждающей многозадачностью и совместной многозадачностью ...
Сон отключает весь карнавал, потому что на самом деле все аттракционы проходят в одну линию, и вы закрыли ворота. Думайте об этом как о «интерпретаторе JS и некоторых других вещах» и игнорируйте потоки ... для вас есть только один поток, ...
... так что не блокируйте это.
источник