Почему node.js асинхронный?
Никто фактически не спрашивал об этом (из всех "предложений", которые я получаю, а также из поиска, прежде чем я спросил здесь).
Так почему же node.js асинхронный?
Из того, что я вывел после некоторого исследования:
Такие языки, как PHP и Python, являются языками сценариев (я могу ошибаться в отношении реальных языков, которые являются языками сценариев), в то время как JavaScript - нет. (Я полагаю, это связано с тем, что JS не компилируется?)
Node.js работает в одном потоке, в то время как языки сценариев используют несколько потоков.
Асинхронный означает отсутствие состояния и что соединение является постоянным, в то время как синхронное является (почти) противоположным.
Может быть, ответ найден где-то выше, но я все еще не уверен.
Мой второй и последний вопрос, связанный с этой темой:
Можно ли сделать JavaScript синхронным языком?
PS. Я знаю, что некоторые из вас спросят "почему вы хотите сделать JS синхронным?" в ваших ответах, но правда в том, что я не знаю. Я просто задаю такие вопросы, потому что я уверен, что есть больше людей, чем я сам, которые думали о таких вопросах.
3 ответа
Node.js работает в одном потоке, в то время как языки сценариев используют несколько потоков.
Не технически. Node.js использует несколько потоков, но только один поток выполнения. Фоновые потоки предназначены для работы с IO, чтобы заставить все асинхронное совершенство работать. Эффективно работать с потоками - непростая задача, поэтому следующий лучший вариант - запустить цикл обработки событий, чтобы код мог работать, пока фоновые потоки блокируются при вводе-выводе.
Асинхронный означает отсутствие состояния и что соединение является постоянным, в то время как синхронное является (почти) противоположным.
Не обязательно. Вы можете легко сохранить состояние в асинхронной системе. Например, в Javascript вы можете использовать bind()
связать this
к функции, тем самым сохраняя состояние явно, когда функция возвращает:
function State() {
// make sure that whenever doStuff is called it maintains its state
this.doStuff = this.doStuff.bind(this);
}
State.prototype.doStuff = function () {
};
Асинхронный означает не ожидание завершения операции, а регистрацию слушателя. Это происходит постоянно на других языках, особенно во всем, что должно принимать входные данные от пользователя. Например, в Java GUI вы не блокируете ожидание нажатия пользователем кнопки, а регистрируете слушателя в GUI.
Мой второй и последний вопрос, связанный с этой темой:
Можно ли сделать JavaScript синхронным языком?
Технически все языки синхронны, даже Javascript. Тем не менее, Javascript работает намного лучше в асинхронном дизайне, потому что он был разработан, чтобы быть однопоточным.
В основном есть два типа программ:
- Процессор привязан - единственный способ сделать это быстрее, это получить больше процессорного времени
- IO тратит много времени на ожидание данных, поэтому более быстрый процессор не будет иметь значения
Видеоигры, средства обработки чисел и компиляторы связаны с процессором, тогда как веб-серверы и графические интерфейсы обычно связаны с вводом-выводом. Javascript относительно медленный (из-за того, насколько он сложен), поэтому он не сможет конкурировать в сценарии с привязкой к процессору (поверьте мне, я написал свою долю Javascript с привязкой к процессору).
Вместо кодирования в терминах классов и объектов, Javascript поддается кодированию в виде простых функций, которые можно связать вместе. Это работает очень хорошо в асинхронном дизайне, потому что алгоритмы могут быть написаны для постепенной обработки данных по мере их поступления. IO (особенно сетевой IO) очень медленный, поэтому между пакетами данных существует довольно много времени.
пример
Предположим, у вас есть 1000 активных соединений, каждое из которых доставляет пакет каждую миллисекунду, а обработка каждого пакета занимает 1 микросекунду (очень разумно). Давайте также предположим, что каждое соединение отправляет 5 пакетов.
В однопоточном синхронном приложении каждое соединение будет обрабатываться последовательно. Общее время составляет (5*1 + 5*.001) * 1000 миллисекунд или ~5005 миллисекунд.
В однопоточном асинхронном приложении каждое соединение будет обрабатываться параллельно. Поскольку каждый пакет занимает 1 миллисекунду, а обработка каждого пакета занимает 0,001 миллисекунды, мы можем обрабатывать каждый пакет соединения между пакетами, поэтому наша формула принимает вид: 1000*.001 + 5*1 миллисекунды или ~6 миллисекунд.
Традиционным решением этой проблемы было создание большего количества потоков. Это решило проблему ввода-вывода, но затем, когда число подключений возросло, увеличились и использование памяти (потоки требуют много памяти) и использование процессора (мультиплексирование 100 потоков на 1 ядро сложнее, чем 1 потока на 1 ядре).
Однако есть и минусы. Если вашему веб-приложению также необходимо выполнить какое-то сложное сокращение числа, вы SOL, потому что пока вы обрабатываете числа, соединения должны ждать. Потоки решают эту проблему, потому что ОС может заменить вашу задачу, интенсивно использующую процессор, когда данные готовы для потока, ожидающего ввода-вывода. Кроме того, node.js связан с одним ядром, поэтому вы не можете использовать преимущества своего многоядерного процессора, если не раскручиваете несколько экземпляров и запросы прокси.
Javascript не компилируется ни во что. Он "оценивается" во время выполнения, как PHP и Ruby. Поэтому это язык сценариев, такой же, как PHP/Ruby. (это официальное название на самом деле ECMAScript).
"Модель", которой придерживается Node, немного отличается от PHP/Ruby. Node.js использует "цикл обработки событий" (единый поток), который преследует одну цель: принимать сетевые запросы и обрабатывать их очень быстро, и если по какой-либо причине он сталкивается с операцией, которая занимает некоторое время (запрос API, запрос базы данных - в основном все, что связано с IO (ввод / вывод)), он передает это фоновому "рабочему" потоку и уходит, чтобы сделать что-то еще, пока рабочий поток ожидает завершения длинной задачи. Когда это произойдет, основной "цикл обработки событий" возьмет результаты и продолжит работу с ними.
PHP / Ruby, следуя модели потоков. По сути, для каждого входящего сетевого запроса сервер приложений раскручивает выделенный поток или процесс для обработки запроса. Это не очень хорошо масштабируется, и подход Node упоминается как одна из его сильных сторон по сравнению с этой моделью.
Асинхронный означает отсутствие состояния и что соединение является постоянным, в то время как синхронное является (почти) противоположным.
Нет. Синхронные инструкции выполняются в естественном порядке, от первого до последнего. Асинхронные инструкции означают, что если этап в потоке программы занимает относительно длительное время, программа продолжит выполнение операций и просто вернется к этой операции после завершения.
Можно ли сделать JavaScript синхронным языком?
Некоторые операции в JavaScript являются синхронными. Другие асинхронны. Например:
Операции блокировки:
for(var k = 0; k < 1; k = k - 1;){
alert('this will quickly get annoying and the loop will block execution')
alert('this is blocked and will never happen because the above loop is infinite');
Асинхронный:
jQuery.get('/foo', function (result) { alert('This will occur 2nd, asynchronously'); });
alert('This will occur 1st. The above operation was skipped over and execution continued until the above operation completes.');
Можно ли сделать JavaScript синхронным языком?
Javascript не является "асинхронным языком"; скорее, в node.js много асинхронных API. Асинхронность - это свойство API, а не языка. Простота, с которой функции могут создаваться и передаваться в javascript, делает удобной передачу функций обратного вызова, что является одним из способов обработки потока управления в асинхронном API, но нет ничего изначально асинхронного в javascript. Javascript может легко поддерживать синхронные API.
Почему node.js асинхронный?
Node.js поддерживает асинхронные API, потому что он однопоточный. Это позволяет ему эффективно управлять собственными ресурсами, но требует, чтобы длительные операции были неблокирующими, а асинхронные API-интерфейсы - это способ управления потоком с большим количеством неблокирующих операций.