Цикл Событий Nodejs


существуют ли внутренне два цикла событий в архитектуре nodejs?

  • libev/libuv
  • V8 javascript event loop

при запросе ввода-вывода узел помещает запрос в очередь libeio, который, в свою очередь, уведомляет о доступности данных через события с помощью libev и, наконец, эти события обрабатываются циклом событий v8 с помощью обратных вызовов?

в принципе, как libev и libeio интегрированы в архитектуру nodejs?

есть ли документация доступна, чтобы дать четкое представление о внутренней архитектуре nodejs?

5 122

5 ответов:

Я лично читал исходный код узла.js & v8.

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

что я публикую здесь это мое понимание узел.js, и это может быть немного не так.

  1. Libev это цикл событий, который фактически выполняется внутри узла.js для выполнения простых операций цикла событий. Это написано первоначально для систем *nix. Libev предоставляет простой, но оптимизированный цикл событий для выполнения процесса. Вы можете прочитать больше о libev здесь.

  2. LibEio библиотека для асинхронного выполнения ввода-вывода. Он обрабатывает файловые дескрипторы, обработчики данных, сокеты и т. д. Вы можете прочитать больше об этом здесь здесь.

  3. LibUv - это слой абстракции в верхней части libeio , libev, c-ares (для DNS ) и iocp (для Windows asynchronous-io). LibUv выполняет, поддерживает и управляет всеми операциями ввода-вывода и событиями в пуле событий. (в случае libeio threadpool ). Вы должны проверить учебник Райана Даля на libUv. Это начнет иметь больше смысла для вас о том, как libUv работает сам, а затем вы поймете, как узел.js работает на верхней части libuv и v8.

чтобы понять только цикл событий javascript, вы должны рассмотреть смотрите эти видео!--5-->

чтобы увидеть, как 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) используются для работы с файлами, в то время как управляемая событиями абстракция работает без изменений, с точки зрения программы.

надеюсь, что это помогает.

введение в libuv

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 извлекает поток из пула потоков и выполняет функцию там вместо основного потока цикла событий. Это предотвращает блокировку ввода-вывода от задержки остальных событий в очереди событий.

существует только один цикл событий, предоставляемый libuv, V8-это просто JS runtime engine.