• Как происходит исполнение кода в Event Loop и управление потоками для веб приложений?

    bingo347
    @bingo347 Куратор тега Node.js
    Crazy on performance...
    1. Как происходит связь между кодом js, c++. На самом гитхабе Nodejs можно открыть папки с функциями, которые я импортирую в коде. А также их реализации в файлах .cc расширения. Но не могли бы подробнее описать механизм, которые позволяет 2 разных языка использовать.
    JS движок (например V8) предоставляет платформе (Node.js) некоторый C++ api, через который платформа может движком управлять. Например через это api можно дать движку строчку с JS кодом и попросить его выполнить, а в ответ получить указатель на результат выполнения (V8 например возвращает результат последнего выражения в коде). Так же, если у нас есть указатель на JS функцию, можно попросить движок ее выполнить с определенными аргументами и this, а в ответ получить результат этого выполнения (функция что-то вернула или бросила исключение). Ну и наконец, мы можем дать этому api указатель на C/C++ функцию, а движок сделает из нее JS функцию и вернет указатель на нее, когда JS функция вызывается движок вызовет нашу C/C++ функцию и даст ей на вход контекст выполнения, из которого можно извлечь this и аргументы функции, так же через контекст можно установить результат выполнения JS функции, указав что JS функция должна вернуть некоторое JS значение или бросить некоторое исключение.

    2. V8 - движок для исполнения JS кода, то есть превращения его в машинный код для исполнения комманд. Libuv написана на с++. Они же не работают в паре? Я так понимаю, что часть кода исполняется на движке v8, а различные асинхронные вызовы, которые через Nodejs api делегируются библиотеке Libuv - уже от неё превращаются в низкоуровневый машинный код, который исполняется компьютеров?Можете чуть пролить свет на исполнения уже между этими компонентами Libuv, V8.
    V8 ничего не знает о libuv, как и libuv ничего не знает о V8.
    V8 занимается компиляцией/интерпретацией/выполнением JS кода, управлением JS памятью и некоторыми другими связанными с JS вещами. В V8 нет никаких event loop и чего-то подобного, он запускает JS код только когда ему об этом скажет платформа (например Node.js).
    Libuv занимается асинхронными операциями. Что-то переадресует операционной системе, например сетевые сокеты можно собрать в пачку и отдать в epoll в Linux или kqueue в MacOS, заблокировав лишь один поток сразу на тысячи сокетов. А что-то просто блокируется на фоновых потоках, например обращения к файловой системе. Event loop нет и здесь, но зато есть очередь задач, которые потенциально готовы.
    Ну и наконец сама платформа (Node.js) реализует event loop (по сути просто бесконечный цикл), в котором получает потенциально готовые задачи от libuv и раскладывает по своим очередям готовые, а неготовые планирует в libuv, спрашивает у V8 не хочет ли он сделать сборку мусора, ну и наконец говорит V8 вызвать некоторые JS функции.

    3. После того, как Nodejs передает асинхронный вызов Libuv на исполнение. То callback функция помещается позже в стэк для исполнения, а исполнятся начинается после того, как система просигнализирует о завершении процесса, например считывания файла. Или вначале считывается файл, а потом система об этом сигнализирует и помещается callback функция в стэк Event Loop'a для исполнения?
    Выше уже расписал как Node.js взаимодействует с libuv в теле event loop, так же расписал как JS код может вызвать C++ функцию. Рассмотрим на сильно упрощенном примере, что происходит когда в JS коде на Node.js мы вызываем fs.readFile(filepath, callback):
    1. fs.readFile - это обычная JS функция, но внутри она вызывает некоторую C++ функцию из Node.js, которая получает указатель на строку filepath и указатель на JS функцию callback, но эта C++ функция будет запущена на том же потоке где и event loop (по сути где-то внутри цикла), а блокировать нам нельзя. Поэтому она просто планирует вызов другой C++ функции на фоновых потоках и завершается, возвращая тем самым управление JS коду.
    2. В какой-то момент до запланированной C++ функции дойдет очередь на выполнение на одном из фоновых потоков, она прочитает файл в память и добавит в очередь готовых задач некоторый объект, который является результатом операции чтения из файла, этот объект будет хранить в себе указатель на прочитанные данные и указатель на JS функцию callback.
    3. Еще через некоторое время поток с event loop извлечет из очереди этот объект результат и скажет V8 вызвать функцию callback с данными из файла.

    4. Можете более подробней рассказать про исполнение кода на инстансах приложения в зависимости от количества ядер процессора и управления потоками:

    4.1 Есть к примеру приложений на Nodejs. На компьютере 4 ядра. Я на каждом ядре могу запустить инстанс этого приложения. И у каждого инстанса в pool thread'e будет по 4 потока дополнительных, которые создаются по умолчанию?
    Каждый инстанс Node.js - это отдельный процесс операционной системы. У каждого процесса своя изолированная память. И да, каждый может запускать несколько потоков (у Node.js кстати 4 потока - это минимум, при большой нагрузке она может добавить в пул до 128 потоков), но в случае с Node.js большая часть потоков почти всегда что-то ждут (пока тот же файл прочитается например) и почти не тратят ресурсы CPU, а активно работает лишь один - тот в котором event loop.

    4.2 Если отойти от ноды и запустить приложение на php фреймворке на Apache и этот сервер выделяет под каждый запрос свой поток.В данном случае - это такой же условно поток, который может выделяться и библиотекой Libuv или это абсолютно разные понятия? И сколько инстансов php приложения запущено, когда Apache под каждый создает свой поток? Как соотносится поток с инстансом приложения на php.
    С точки зрения операционной системы - да, это такие же потоки. Разница заключается в том, что в этих потоках происходит. В php только 1 поток, который то что-то полезное делает, то ждет ответа от БД/файловой системы/еще чего-то. А в Node.js это разделено, 1 поток занят только полезной работой (выполнением JS кода) и несколько только ждут ответа.
    Насчет какие там лимиты на количество инстансов php у Apache я не скажу, но они точно не бесконечные, а значит если лимит будет исчерпан, то клиенты (браузер) будут ждать пока какой-то из инстансов php не завершит свою работу полностью. А в node.js мы на одном инстансе можем обслуживать сразу множество клиентов, выполняя задачи для каждого по чуть-чуть, пока для одного клиента ждем ответ из БД можем заняться обработкой запроса от другого клиента.

    4.3 Может в дополнение расскажите про потоки в системе, их ограничения и т.д
    Тут целую лекцию можно читать. Думаю это стоит вынести в отдельный вопрос.
    Ответ написан
    3 комментария
  • Как самостоятельно разобраться в архитектуре npm пакета?

    Sanasol
    @Sanasol Куратор тега Веб-разработка
    нельзя просто так взять и загуглить ошибку
    Через отладчик смотрите запуски, пытаетесь понять понять какие паттерны были применены. Для меня просто как черный ящик относительно код пакета, но я понимаю, что как раз надо исследовать и понимать как оно устроено.


    Какой отладчик и черный ящик.
    Код буквально лежит в на гитхабе на который ссылку приложили или в node_modules локально

    Вопрос в том как пройтись по папкам и разобраться?
    Как обычно с любым проектом.
    npm пакетность это про то что в package.json добавлено пара строк и "загружено" на npmjs
    В остальном это обычный проект как любой фронт сайта или чего бы то ни было.

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

    Секунд 15 заняло найти параметр imageUploadUrl в readme для загрузки файлов на сервер, а не через base64.
    Ответ написан
    8 комментариев