Привет, Дипал Джаясекара.

Спасибо, что ответили на мои вопросы в одном из ваших предыдущих сообщений в блоге. Ваш вклад был действительно полезен. Я очень ценю это!

У меня снова есть несколько вопросов. Было бы здорово, если бы вы помогли мне еще раз прояснить некоторые вещи.

  1. У меня вопрос по ручкам и запросам. Вы писали о них несколько раз в своем посте. Например:

uv__loop_alive — Проверяет, есть ли какие-либо обработчики, на которые есть ссылки, которые нужно вызвать, или какие-либо активные ожидающие операции

Or:

Если нет активных дескрипторов или ожидающих активных операций, нет смысла ждать, поэтому тайм-аут равен 0.

Они используются в некоторых функциях. В этом:

И этот:

Я не понимаю, что проверяют функции uv__has_active_handles и uv__has_active_reqs? Что такое ссылочные обработчики и активные запросы/операции (как я вижу, вы используете запросы и операцию взаимозаменяемо )?

Про дескрипторы и запросы я уже читал в документации Libuv, но до сих пор не могу понять. Трудно понять без реальных словесных примеров. Может быть, обработчик — это что-то вроде fs, а запрос/операция — просто http запрос? Обработчики вызываются в пуле потоков Libuv, а любые запросы/операции обрабатываются в AIO ядра (например, epoll в Linux)?

Вот как я понимаю: функция uv__has_active_handles проверяет, есть ли какие-то незавершенные задачи в пуле потоков Libuv (например, чтение содержимого файла с помощью fs). Если есть незавершенные задачи, эта функция возвращает true. Как только эти задачи будут завершены, соответствующие события будут запущены, а их обратные вызовы будут добавлены в файл pending_queue. Та же логика с запросами/операциями (но uv__has_active_reqs проверяет, нет ли недоделок на AIO ядра). Я не уверен, прав я или нет.

2. Вы написали:

Если pending_queue пусто, эта функция вернет 0. В противном случае будут выполнены все обратные вызовы в pending_queue, и функция вернет 1.

К этой фразе вопросов нет. Прекрасно это понимаю. Вопрос в том, почему режим UV_RUN_ONCE зависит от результата функции uv__run_pending? Вы написали:

Если цикл событий выполняется на UV_RUN_ONCE и если uv_run_pending возвращает 0 (т. е. pending_queue пусто), timeout вычисляется с использованием метода uv_backend_timeout.

Какая разница для цикла обработки событий, работающего в режиме UV_RUN_ONCE, был ли был некоторый обратный вызов в режиме pending_queue или нет? Если возвращается 0, это означает, что обратных вызовов не было. Если возвращается 1, это означает, что были какие-то обратные вызовы, но в любом случае — они были выполнены. Почему мы не можем дождаться опроса ввода-вывода, если раньше в pending_queue были какие-то обратные вызовы. В любом случае, мы их выполнили, и pending_queue будет пустым.

3. Вы написали:

Если есть ожидающие выполнения дескрипторы бездействия, ожидание ввода-вывода не должно выполняться.

Что это за холостые ручки? К сожалению, я не нашел никакой информации об этом этапе в ваших сообщениях. Насколько я понимаю, они выполняются в течение этой фазы uv__run_idle. Не могли бы вы привести пример из мира Node.js? Обратные вызовы setImmediate выполняются на этапе uv__run_check… а какие обратные вызовы выполняются на этапе uv__run_idle?

4. Также, не могли бы вы рассказать нам что-нибудь о фазе uv__run_prepare?

5. В каком режиме по умолчанию работает цикл обработки событий? К сожалению, никакой информации об этом здесь я не нахожу. Какой из них наиболее эффективен для приложений Node.js? Или это зависит?

Большое спасибо за ваше время!