Цикл Событий Nodejs
существуют ли внутренне два цикла событий в архитектуре nodejs?
- libev/libuv
- V8 javascript event loop
при запросе ввода-вывода узел помещает запрос в очередь libeio, который, в свою очередь, уведомляет о доступности данных через события с помощью libev и, наконец, эти события обрабатываются циклом событий v8 с помощью обратных вызовов?
в принципе, как libev и libeio интегрированы в архитектуру nodejs?
есть ли документация доступна, чтобы дать четкое представление о внутренней архитектуре nodejs?
5 ответов:
Я лично читал исходный код узла.js & v8.
Я пошел в аналогичную проблему, как вы, когда я пытался понять узел.архитектура js для записи собственных модулей.
что я публикую здесь это мое понимание узел.js, и это может быть немного не так.
Libev это цикл событий, который фактически выполняется внутри узла.js для выполнения простых операций цикла событий. Это написано первоначально для систем *nix. Libev предоставляет простой, но оптимизированный цикл событий для выполнения процесса. Вы можете прочитать больше о libev здесь.
LibEio библиотека для асинхронного выполнения ввода-вывода. Он обрабатывает файловые дескрипторы, обработчики данных, сокеты и т. д. Вы можете прочитать больше об этом здесь здесь.
LibUv - это слой абстракции в верхней части libeio , libev, c-ares (для DNS ) и iocp (для Windows asynchronous-io). LibUv выполняет, поддерживает и управляет всеми операциями ввода-вывода и событиями в пуле событий. (в случае libeio threadpool ). Вы должны проверить учебник Райана Даля на libUv. Это начнет иметь больше смысла для вас о том, как libUv работает сам, а затем вы поймете, как узел.js работает на верхней части libuv и v8.
чтобы понять только цикл событий javascript, вы должны рассмотреть смотрите эти видео!--5-->
- JS-конференция
- JSConf2011 ( имеет очень раздражительный sfx)
- понимание событийного программирования
- понимание узел.цикл событий js
чтобы увидеть, как libeio используется с узлом.js для создания асинхронных модулей вы должны увидеть .
в основном то, что происходит внутри узел.js заключается в том, что цикл v8 запускает и обрабатывает все части javascript, а также модули C++ [когда они работают в основном потоке ( согласно узлу официальной документации.сам JS является однопоточным) ]. Когда он находится вне основного потока, libev и libeio обрабатывают его в пуле потоков, а libev обеспечивает взаимодействие с основным циклом. Так что, насколько я понимаю, узел.js имеет 1 постоянный цикл событий: это цикл событий v8. Чтобы справиться с задачами++ асинхронность это с помощью класса ThreadPool [через libeio & libev ].
например:
eio_custom(Task,FLAG,AfterTask,Eio_REQUEST);
, который появляется во всех модулях обычно вызов функции
Task
в пуле потоков. Когда он будет завершен, он вызываетAfterTask
функция в основном потоке. Тогда какEio_REQUEST
является обработчиком запроса, который может быть структурой / объектом, мотив которого заключается в обеспечении связи между threadpool и основным потоком.
похоже на некоторые из обсуждаемых сущностей (например: libev и т. д.) уже потеряли актуальность, в связи с тем, что прошло некоторое время, но я думаю, что вопрос еще имеет большой потенциал.
позвольте мне попытаться объяснить работу событийной модели с помощью абстрактного примера, в абстрактной среде UNIX, в контексте узла, на сегодняшний день.
программы:
- скриптовый движок запускает выполнение скрипт.
- каждый раз, когда встречается операция привязки ЦП, она выполняется inline (real machine), в ее полноте.
- каждый раз, когда обнаруживается операция привязки ввода-вывода, запрос и его обработчик завершения регистрируются с помощью "механизма событий" (виртуальной машины)
- повторите операции таким же образом выше, пока скрипт не закончится. Граница эксплуатации процессора - выполнить в строке, ввода/вывода, просят от машин, как и выше.
- Когда I / O завершается, слушатели перезваниваются.
механизм событий выше называется libuv AKA event loop framework. Узел использует эту библиотеку для реализации своей модели программирования, управляемой событиями.
узла:
- есть один поток для размещения среды выполнения.
- возьмите пользовательский скрипт.
- скомпилируйте его в native [ leverage v8]
- загрузите двоичный файл и перейдите в запись точка.
- скомпилированный код выполняет связанные с ЦП действия в строке, используя примитивы программирования.
- многие коды ввода-вывода и таймера имеют собственные обертки. Например, сетевой ввод / вывод
- таким образом, вызовы ввода-вывода маршрутизируются из скрипта в мосты C++, причем дескриптор ввода-вывода и обработчик завершения передаются в качестве аргументов.
- машинный код выполняет цикл libuv. Он получает цикл, ставит в очередь событие низкого уровня, которое представляет ввод-вывод, и родной оболочка обратного вызова в структуру цикла libuv.
- машинный код возвращается в скрипт - в данный момент не происходит ввода-вывода!
- элементы выше повторяются много раз, пока не будут выполнены все коды не-ввода/вывода, и все коды ввода/вывода будут зарегистрированы в libuv.
- наконец, когда в системе ничего не осталось для выполнения, узел передает управление libuv
- libuv вступает в действие, он собирает все зарегистрированные события, запрашивает операционная система, чтобы получить их работоспособность.
- те, которые готовы к вводу/выводу в неблокирующем режиме, подбираются, ввод/вывод выполняется, и их обратные вызовы выдаются. Один за другим.
- те, которые еще не готовы (например, чтение сокета, для которого другая конечная точка еще ничего не написала), будут продолжать зондироваться с ОС, пока они не будут доступны.
- цикл внутренне поддерживает постоянно увеличивающийся таймер. Когда приложение запрашивает для отложенного обратного вызова (например, setTimeout) это значение внутреннего таймера используется для вычисления правильного времени для запуска обратного вызова.
в то время как большинство функций обслуживаются таким образом, некоторые (асинхронные версии) файловых операций выполняются с помощью дополнительных потоков, хорошо интегрированных в libuv. В то время как сетевые операции ввода-вывода могут ждать в ожидании внешнего события, такого как другая конечная точка, отвечающая данными и т. д. папка операции требуют некоторой работы от самого узла. Например, если вы откроете файл и подождете, пока fd будет готов с данными, этого не произойдет, так как никто не читает на самом деле! В то же время, если Вы читаете из файла, встроенного в основной поток, он может потенциально блокировать другие действия в программе и может создавать видимые проблемы, поскольку операции с файлами очень медленные по сравнению с действиями, связанными с ЦП. Таким образом, внутренние рабочие потоки (настраиваемые через переменную среды UV_THREADPOOL_SIZE) используются для работы с файлами, в то время как управляемая событиями абстракция работает без изменений, с точки зрения программы.
надеюсь, что это помогает.
The узел.js проект начался в 2009 году как среда JavaScript, отделенная от браузера. Использование Google V8 и Марка Лемана libev узел.js объединил модель ввода / вывода – evented-с языком, который хорошо подходил к стилю программирования; из-за того, как он был сформирован браузерами. Как узел.js рос в популярности, важно было заставить его работать на Windows, но libev работал только на Unix. Эквивалентом Windows механизмов уведомления о событиях ядра, таких как kqueue или (e)poll, является IOCP. libuv был абстракцией вокруг libev или IOCP в зависимости от платформы, предоставляя пользователям API на основе libev. В узле-v0. 9. 0 версия libuv libev были удалены.
также одно изображение, которое описывает цикл событий в узле.js by @BusyRich
обновление 05/10/2017
в данном документе узел.цикл событий js,
на следующей диаграмме показан упрощенный обзор порядка операций цикла событий.
┌───────────────────────┐ ┌─>│ timers │ │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ │ │ I/O callbacks │ │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ │ │ idle, prepare │ │ └──────────┬────────────┘ ┌───────────────┐ │ ┌──────────┴────────────┐ │ incoming: │ │ │ poll │<─────┤ connections, │ │ └──────────┬────────────┘ │ data, etc. │ │ ┌──────────┴────────────┐ └───────────────┘ │ │ check │ │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ └──┤ close callbacks │ └───────────────────────┘
Примечание: каждое поле будет называться "фазой" цикла событий.
Обзор Фаз
- таймеры: эта фаза выполняет обратные вызовы, запланированные
setTimeout()
иsetInterval()
.- I / O обратные вызовы: выполняет почти все обратные вызовы, за исключением
- закрыть обратных вызовов, те, которые запланированы таймеры, и
setImmediate()
. холостой ход, подготовка: используется только внутри.- опрос: получить новые события ввода-вывода; узел будет блокировать здесь, когда это необходимо.
- Регистрация:
setImmediate()
обратные вызовы вызываются здесь.- закрыть обратных вызовов, например:
socket.on('close', ...)
.между каждым запуском цикла событий, узел.js проверяет, ожидает ли он асинхронного ввода-вывода или таймеров и выключается чисто, если их нет.
существует один цикл событий в архитектуре NodeJs.
узел.JS Event Loop Model
приложения узла выполняются в однопоточной модели, управляемой событиями. Однако, узел реализует пул потоков в фоновом режиме, так что работа может быть выполнена.
узел.js добавляет работу в очередь событий, а затем имеет один поток, выполняющий цикл событий, чтобы забрать его. Цикл событий захватывает верхний элемент в очереди событий, выполняет его, а затем захватывает следующий элемент.
при выполнении кода, который дольше живет или блокирует ввод-вывод, вместо прямого вызова функции он добавляет функцию в очередь событий вместе с обратным вызовом, который будет выполнен после завершения функции. Когда все события на узле.очередь событий js была выполнена, узел.приложения на JS прекращается.
цикл событий начинает сталкиваться с проблемами, когда наши функции приложения блокируются на I / O.
узел.js использует обратные вызовы событий, чтобы избежать необходимо дождаться блокировки ввода-вывода поэтому все запросы, которые выполняют блокировку ввода-вывода, выполняются в другом потоке в фоновом режиме.
когда событие, которое блокирует ввод-вывод, извлекается из очереди событий, узел.js извлекает поток из пула потоков и выполняет функцию там вместо основного потока цикла событий. Это предотвращает блокировку ввода-вывода от задержки остальных событий в очереди событий.