Ответ 1
Многие вещи требуют времени, например. ожидания в сетевом сокете, чтение файловой системы, системный вызов и т.д. Поэтому многие языки, или, точнее, их стандартная библиотека, включают асинхронную версию своих функций (часто в дополнение к синхронной версии), так что ваши программа в состоянии сделать что-то еще в среднем.
В node.js все еще более экстремально. Они используют однопоточный цикл событий и поэтому должны гарантировать, что ваша программа никогда не блокирует. Они имеют очень хорошо написанную стандартную библиотеку, которая строится вокруг концепции асинхронности, и они используют обратные вызовы, чтобы уведомить вас, когда что-то будет готово. Код в основном выглядит следующим образом:
doSomething1(arg1, arg2, function() {
doSomething2(arg1, arg2, function() {
doSomething3(function() {
// done
});
});
});
somethingElse();
doSomething1
может занять много времени (потому что ему нужно читать из сети, например), но ваша программа все равно может выполнить somethingElse
в среднем времени. После выполнения doSomething1
вы хотите вызвать doSomething2
и doSomething3
.
С другой стороны, основывается на концепции goroutines и каналов (google для "Коммуникации последовательных процессов", если вы хотите больше узнать об абстрактной концепции). Горотины очень дешевы (вы можете одновременно запустить несколько тысяч из них), и поэтому вы можете использовать их везде. Тот же код может выглядеть так: Go:
go func() {
doSomething1(arg1, arg2)
doSomething2(arg1, arg2)
doSomething3()
// done
}()
somethingElse()
В то время как node.js фокусируются на предоставлении только асинхронных API, Go обычно рекомендует вам писать только синхронные API (без обратных вызовов или каналов). Вызов doSomething1
заблокирует текущий goroutine, а doSomething2
будет выполнен только после завершения doSomething1
. Но это не проблема в Go, поскольку обычно доступны другие goroutines, которые можно планировать для запуска в системном потоке. В этом случае somethingElse
является частью другого goroutine и может выполняться тем же способом, что и в примере node.js.
Я лично предпочитаю код Go, так как его легче читать и рассуждать. Другим преимуществом Go является то, что он также хорошо работает с вычислительными тяжелыми задачами. Если вы начнете тяжелое вычисление в node.js, которому не нужно ждать сети вызовов файловой системы, это вычисление в основном блокирует цикл событий. Go scheduler, с другой стороны, сделает все возможное, чтобы отправить goroutines на несколько системных потоков, и ОС может запускать эти потоки параллельно, если ваш процессор поддерживает его.