Что такое неблокирующий или асинхронный ввод-вывод в Node.js?

В контексте механизмов Javascript на стороне сервера, что такое неблокирующий ввод-вывод или асинхронный ввод-вывод? Я считаю, что это упоминается как преимущество перед реализациями на стороне сервера Java.


person Anand    schedule 13.05.2012    source источник
comment
Чтобы понять эту концепцию, полезно подумать о тегах скриптов в среде браузера. У Закаса есть отличная статья об этом - первых нескольких разделов должно быть достаточно, чтобы объяснить концепцию блокировки: nczonline.net/blog/2010/08/10/what-is-a-non-blocking-script   -  person netpoetica    schedule 14.07.2014


Ответы (2)


Синхронный против асинхронного

Синхронное выполнение обычно относится к последовательному выполнению кода. Асинхронное выполнение относится к выполнению, которое не выполняется в той последовательности, в которой оно отображается в коде. В следующем примере синхронная операция вызывает последовательное срабатывание предупреждений. В асинхронной операции, хотя кажется, что alert(2) выполняется вторым, это не так.

Синхронный: 1,2,3

alert(1);
alert(2);
alert(3);

Асинхронный: 1,3,2

alert(1);
setTimeout(() => alert(2), 0);
alert(3);

Блокирование против неблокирования

Блокировка относится к операциям, которые блокируют дальнейшее выполнение до завершения этой операции. Неблокирующий относится к коду, который не блокирует выполнение. В данном примере localStorage - это операция блокировки, поскольку она останавливает выполнение для чтения. С другой стороны, fetch - это неблокирующая операция, поскольку она не останавливает выполнение alert(3).

// Blocking: 1,... 2
alert(1);
var value = localStorage.getItem('foo');
alert(2);

// Non-blocking: 1, 3,... 2
alert(1);
fetch('example.com').then(() => alert(2));
alert(3);

Преимущества

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

Пример синхронной блокировки

Примером синхронных блокирующих операций является то, как некоторые веб-серверы, такие как серверы на Java или PHP, обрабатывают запросы ввода-вывода или сетевые запросы. Если ваш код читает из файла или базы данных, ваш код «блокирует» выполнение всего после него. В этот период ваша машина удерживает память и время обработки для потока, который ничего не делает.

Чтобы обслуживать другие запросы, пока этот поток остановился, зависит от вашего программного обеспечения. Что делает большинство серверного программного обеспечения, так это порождает больше потоков для обслуживания дополнительных запросов. Для этого требуется больше памяти и больше обработки.

Асинхронный, неблокирующий пример

Асинхронные неблокирующие серверы, такие как серверы, созданные в Node, используют только один поток для обслуживания всех запросов. Это означает, что экземпляр Node максимально использует один поток. Создатели разработали его, исходя из того, что узким местом являются операции ввода-вывода и сети.

Когда запросы поступают на сервер, они обслуживаются по очереди. Однако, когда обслуживаемый код должен запросить, например, БД, он отправляет обратный вызов во вторую очередь , и основной поток продолжит работу (он не ждет). Теперь, когда операция DB завершается и возвращается, соответствующий обратный вызов извлекается из второй очереди и помещается в третью очередь, где они ожидают выполнения. Когда движок получает возможность выполнить что-то еще (например, когда стек выполнения опорожняется), он берет обратный вызов из третьей очереди и выполняет его.

person Joseph    schedule 13.05.2012
comment
Я не уверен, что понимаю ваш второй абзац в разделе Блокировка в PHP. Вы говорите, что, хотя PHP обычно блокирует ввод-вывод, это не так, потому что ОС автоматически выполняет потоки операций ввода-вывода? Или вы говорите, что это не проблема PHP, потому что PHP автоматически создает новый поток для каждого запроса, поэтому один заблокированный запрос не останавливает всю среду PHP? (Я предполагаю последнее ..) - person dcow; 03.04.2013
comment
подождите, если это имеет в виду последнее, каковы преимущества неблокирующего ввода-вывода PHP (например, responsePHP или что-то еще) перед блокирующим. все еще путаю - person Sunu Pinasthika Fajar; 24.12.2013
comment
@SunuPinasthikaFajar Сам по себе PHP является синхронным, но программное обеспечение сервера позволяет ему выполнять потоки для каждого запроса, таким образом создавая впечатление, что один запрос не блокирует другой. React позволяет запускать только PHP в асинхронном режиме. - person Joseph; 24.12.2013
comment
хорошо понял. программное обеспечение сервера делает это возможным :). благодаря. Другими словами, поскольку серверное программное обеспечение создает поток для каждого запроса, сервер будет потреблять больше ресурсов, таких как оперативная память или процессор, верно? - person Sunu Pinasthika Fajar; 24.12.2013
comment
@JosephtheDreamer Когда вы говорите, что я (NodeJS) вернусь к вам, когда вы (операция ввода-вывода) закончите. А пока я буду делать что-то еще. Означает ли это, что в node.js, когда код запущен, означает ли это, что операция io запускается в фоновом режиме параллельно с вашим кодом javascript? Или когда действительно вызывается асинхронная функция? - person Charlie Parker; 09.02.2014
comment
@CharlieParker Да. Асинхронная операция выполняется параллельно вашему коду. Но обратный вызов, который возвращается к результатам асинхронной операции, ставится в очередь для выполнения в основном коде, когда основной код не занят. - person Joseph; 09.02.2014
comment
Что меня сбивает с толку, так это то, что я обычно слышу, что node.js имеет только один поток. Если это правда, то почему io выполняется параллельно? Если он работает параллельно, я предполагаю, что об этом позаботится операционная система. Правильно? Кстати, спасибо! :) - person Charlie Parker; 09.02.2014
comment
@CharlieParker Вот сообщение, в котором больше говорится о внутреннем устройстве асинхронного механизма. - person Joseph; 09.02.2014
comment
Неблокирование - это то же самое, что асинхронная блокировка? В статье «Проблема C10K» kegel.com/c10k.html автор, кажется, ссылается на две разные вещи. Например, в этом предложении: Это еще не стало популярным в Unix, вероятно, потому, что немногие операционные системы поддерживают асинхронный ввод-вывод, а также, возможно, потому, что это (как неблокирующий ввод-вывод) требует переосмысления вашего приложения. Он, кажется, относит эти два к двум разным вещам. - person user1914692; 29.08.2014
comment
@ user1914692 Вот 2 сообщения, посвященных этому: stackoverflow.com/q/2625493/575527 и stackoverflow.com/q/7931537/575527. В контексте NodeJS это асинхронно в том смысле, что вы запускаете что-то в фоновом режиме и вызывается обратный вызов (ответное сообщение). Это неблокирующий режим в том смысле, что он не останавливает поток. Следовательно, в JS операции в обоих определениях взаимозаменяемы. - person Joseph; 29.08.2014
comment
@Joseph the Dreamer В статье The C10K Problem kegel.com/c10k.html автор рассказывает о сервере. NodeJS - это сервер. Думаю, автор говорит о двух разных вещах. Не могли бы вы взглянуть на статью и сделать несколько замечаний? - person user1914692; 30.08.2014
comment
Вы сказали Now when the DB operation completes and returns, the corresponding callback pulled out of the second queue, но как именно работает эта волшебная штука? Есть ли связь между обратным вызовом (в очереди 2) и процессом, отвечающим за запрос к БД? - person Olivier Boissé; 04.05.2018
comment
@ OlivierBoissé Вы можете найти в Интернете цикл событий JS или посмотреть это видео. - person Joseph; 04.05.2018
comment
Я уже видел это, понял концепцию, но хочу углубиться. Мне интересно, как программа знает, что операция БД завершена, и поэтому она должна вызвать обратный вызов. Из того, что я читал в Интернете, неблокирующий ввод-вывод работает с каналами, поток может читать / записывать часть данных в каналах, не блокируя ввод-вывод для остальных данных. - person Olivier Boissé; 05.05.2018
comment
@ OlivierBoissé Это реализация движка, выходящая за рамки этого вопроса. Вы всегда можете задать вопрос именно об этом. - person Joseph; 05.05.2018

var startTime = new Date().getTime();
var getEndTime = () => {
    var tempEndTime = new Date().getTime();
    var second = (tempEndTime - startTime)/1000
    return `took ${second} sec...to finish\n`
}

console.log('1: start App', getEndTime())
setTimeout(()=>{
    console.log('2: setTimeout', getEndTime())
}, 1000)
console.log('3: End App', getEndTime())

// console -> Process Order:  1 -> 3 -> 2

Пример кода

person Wayne Chiu    schedule 31.08.2016