В чем разница между синхронным и асинхронным программированием (в файле node.js)


189

Я читал nodebeginner И я наткнулся на следующие два фрагмента кода.

Первый:

    var result = database.query("SELECT * FROM hugetable");
    console.log("Hello World");

Второй:

    database.query("SELECT * FROM hugetable", function(rows) {
       var result = rows;
    });
    console.log("Hello World");

Я получаю то, что они должны делать, они запрашивают базу данных, чтобы получить ответ на запрос. А потом console.log('Hello world').

Первый - предположительно синхронный код. И второй - асинхронный код.

Разница между этими двумя частями очень расплывчата для меня. Каким будет выход?

Поиск в Google по асинхронному программированию мне тоже не помог.


41
Stange, вы ничего не нашли с Google, это довольно большая тема. В синхронном программировании каждый шаг выполняется после завершения предыдущего. В асинхронном режиме шаг 2 будет выполнен, даже если шаг 1 не завершен. Функция, которую вы видите определенной во втором примере, называется функцией callBack и будет запущена, как только будет возвращен результат из базы данных, что, вероятно, произойдет после запуска console.log.
Лоран С.

7
@Bartdude Многое было в асинхронном программировании, но нет простого объяснения, что это такое и что это означает на практике.
Азейра

1
@GabrielLlamas Почему мы должны избегать синхронных функций?
Чарли Паркер

3
@CharlieParker Потому что они блокируют цикл обработки событий, а вы теряете все преимущества асинхронной четной модели ввода / вывода. И потому что это плохая практика. Подумайте об этом так: если вы не используете асинхронные функции, почему вы используете Node.js?
Габриэль Ламас

1
@GabrielLlamas, если я выполняю запрос INSERT и хочу использовать последний вставленный идентификатор после database.query(), тогда я должен назвать его синхронно, верно? или какой должен быть подход? (Этот вопрос у меня давно)
Сан

Ответы:


225

Разница в том, что в первом примере программа будет блокироваться в первой строке. Следующая строка ( console.log) должна будет ждать.

Во втором примере , тоconsole.log будет выполнено, запрос обрабатывается. То есть запрос будет обрабатываться в фоновом режиме, в то время как ваша программа выполняет другие действия, и как только данные запроса будут готовы, вы будете делать с ним все, что захотите.

Итак, в двух словах: первый пример будет блокировать, а второй нет.

Вывод следующих двух примеров:

// Example 1 - Synchronous (blocks)
var result = database.query("SELECT * FROM hugetable");
console.log("Query finished");
console.log("Next line");


// Example 2 - Asynchronous (doesn't block) 
database.query("SELECT * FROM hugetable", function(result) {
    console.log("Query finished");
});
console.log("Next line");

Было бы:

  1. Query finished
    Next line
  2. Next line
    Query finished

Примечание.
Хотя сам узел является однопоточным , есть некоторые задачи, которые могут выполняться параллельно. Например, операции с файловой системой происходят в другом процессе.

Вот почему Node может выполнять асинхронные операции: один поток выполняет операции файловой системы, в то время как основной поток Node продолжает выполнять ваш код JavaScript. На управляемом событиями сервере, таком как Node, поток файловой системы уведомляет основной поток Node об определенных событиях, таких как завершение, сбой или прогресс, вместе с любыми данными, связанными с этим событием (например, результатом запроса к базе данных или ошибкой сообщение), и основной поток узлов решает, что делать с этими данными.

Подробнее об этом вы можете прочитать здесь: Как работает однопоточная неблокирующая модель ввода-вывода в Node.js


9
Таким образом, в основном, когда я выполняю первый кусок кода, он делает что-то вроде этого request query.; 5 seconds later when the request is done; console.log:; когда вторая исполняет: request query; console.log; work on the query;
Азейра

1
@JohnGalt sql работает в другом потоке. Но, конечно, это зависит от реализации используемого вами драйвера sql. Драйвер должен создать новый поток, подключиться к mysql и выполнить запрос. После этого отправьте результат в очередь событий , и узел вызовет обратный вызов.
Salvatorelab

4
Разве для асинхронного примера не возможно вывести то же самое, что и # 1? Как, например, database.queryзаканчивается так быстро, что к тому времени, когда мы достигаем, console.logзадача уже выполнена.
greatwolf

2
@TheBronx, если console.log("Next line");в примере 2 находится внутри анонимной функции, поэтому сразу после console.log("query finished");этого это будет означать, что «Следующая строка» будет напечатана ПОСЛЕ «запроса завершено», верно? Таким образом, если бы у меня все было по-вложенному, все работало бы синхронно, поэтому мне не нужно было бы беспокоиться об использовании синхронных версий определенных функций. Я прав в своем понимании?
Абдул

4
Краткий ответ : да @Abdul, вы правы. Длинный ответ : Вложенные функции (обратные вызовы) - это способ делать вещи последовательно, «один за другим». Но это не "синхронно" технически. Анонимная функция по-прежнему выполняется «после завершения операции блокировки» или, другими словами, «асинхронно». Node.js может выполнять другие функции во время этой операции блокировки. Функции остаются асинхронными, просто вы их связываете. Синхронизация функций блокирует выполнение, это ключ.
Salvatorelab

75

Разница между этими двумя подходами заключается в следующем:

Синхронный способ: он ожидает завершения каждой операции, после чего только выполняет следующую операцию. Для вашего запроса: Команда console.log()не будет выполнена, пока & не завершится выполнение запроса, чтобы получить весь результат из базы данных.

Асинхронный способ: он никогда не ожидает завершения каждой операции, скорее он выполняет все операции только в первом GO. Результат каждой операции будет обработан, как только будет доступен результат. По вашему запросу:console.log() будет выполнена вскоре после Database.Query()метода. В то время как запрос к базе данных выполняется в фоновом режиме и загружает результат, как только он завершает получение данных.

Случаи использования

  1. Если ваши операции выполняются не очень тяжело, например, при запросе огромных данных из БД, продолжайте использовать Синхронный способ, в противном случае Асинхронный способ.

  2. В асинхронном режиме вы можете показывать пользователю некоторый индикатор прогресса, а в фоновом режиме вы можете продолжить работу с большим весом. Это идеальный сценарий для приложений с графическим интерфейсом.


2
Означает ли это, что db.query (cmd, callback) работает одновременно (как в потоках)? Работают ли они одновременно?
Чарли Паркер

Во втором его примере, есть ли вероятность того, что запрос завершится так быстро, что он сначала вызовет обратный вызов, прежде чем console.log?
Фахми

@ Фахми теоретически да, практически совершенно невозможно
Лео Месси

24

Это станет более понятным, если вы добавите строку в оба примера:

var result = database.query("SELECT * FROM hugetable");
console.log(result.length);
console.log("Hello World");

Второй:

database.query("SELECT * FROM hugetable", function(rows) {
   var result = rows;
   console.log(result.length);
});
console.log("Hello World");

Попробуйте запустить их, и вы заметите, что первый (синхронный) пример, result.length, будет распечатан ДО строки «Hello World». Во втором (асинхронном) примере длина result.length (наиболее вероятно) будет напечатана ПОСЛЕ строки «Hello World».

Это связано с тем, что во втором примере database.queryсценарий запускается асинхронно в фоновом режиме, и сценарий сразу же продолжается «Hello World». Выполняется console.log(result.length)только после завершения запроса к базе данных.


1
Вы говорите: result.length (скорее всего) будет напечатан ПОСЛЕ строки «Hello World». .... почему это будет только "наиболее вероятно"? Я думаю, что это всегда печатается после вывода console.log. Спасибо за разъяснения :)
человечествоANDpeace

9
@humanityANDpeace: вот и вся точка асинхронного доступа: вы не знаете, когда это будет сделано. Возможно, это нелепо быстрая база данных, и запрос к базе данных возвращается еще до того, как Javascript попадает в строку «Hello World» ...
Martijn

19

Во-первых, я понимаю, что опоздал с ответом на этот вопрос.

Перед обсуждением синхронного и асинхронного, давайте кратко рассмотрим, как работают программы.

В синхронном случае каждое утверждение завершается до запуска следующего оператора. В этом случае программа оценивается именно в порядке заявлений.

Вот как асинхронный работает в JavaScript. В движке JavaScript есть две части: одна часть, которая просматривает код и ставит в очередь операции, а другая обрабатывает очередь. Обработка очереди происходит в одном потоке, поэтому одновременно может выполняться только одна операция.

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

    console.log("Hello World"); 

Запрос к базе данных все еще обрабатывается, но операция console.log находится в начале очереди и обрабатывается. Эта синхронная операция выполняется сразу же, что сразу приводит к выводу «Hello World». Через некоторое время операция базы данных завершается, и только после этого вызывается и обрабатывается обратный вызов, зарегистрированный в запросе, в результате чего значение переменной result устанавливается равным строкам.

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

Простой способ узнать, какая операция JavaScript является асинхронной, - это заметить, требует ли она обратного вызова - обратный вызов - это код, который будет выполнен после завершения первой операции. В двух примерах, приведенных в этом вопросе, мы видим, что только во втором случае есть обратный вызов, поэтому это асинхронная операция двух. Это не всегда так из-за разных стилей обработки результата асинхронной операции.

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

Многие библиотеки, такие как узел 'fs', предоставляют как синхронные, так и асинхронные стили для некоторых операций. В случаях, когда операция не занимает много времени и не используется много - как в случае чтения файла конфигурации - операция синхронного стиля приведет к коду, который будет легче читать.


6

В синхронном случае команда console.log не выполняется, пока не завершится выполнение запроса SQL.

В асинхронном случае команда console.log будет выполнена напрямую. Затем результат запроса будет сохранен функцией «обратного вызова» через некоторое время.


1
Но на самом деле вызывается одновременно? Что меня смущает, так это то, что в асинхронном коде реальный код выполняется в то же время параллельно?
Чарли Паркер

Это зависит от процессора (многоядерный?) И операционной системы. См. En.wikipedia.org/wiki/Multithreading_(software)#Multithreading
связано

4

Основное отличие заключается в асинхронном программировании, иначе вы не остановите выполнение. Вы можете продолжить выполнение другого кода, пока выполняется «запрос».


2

Функция делает второй асинхронным.

Первый заставляет программу ждать завершения каждой строки, прежде чем продолжить следующую. Второй позволяет каждой линии работать вместе (и независимо) одновременно.

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


0

Программирование синхронизации

Языки программирования, такие как C, C #, Java - это синхронное программирование, поэтому все, что вы пишете, будет выполняться в порядке написания.

-GET DATA FROM SQL.
//Suppose fetching data take 500 msec

-PERFORM SOME OTHER FUNCTION.
//Performing some function other will take 100 msec, but execution of other 
//task start only when fetching of sql data done (i.e some other function 
//can execute only after first in process job finishes).

-TOTAL TIME OF EXECUTION IS ALWAYS GREATER THAN (500 + 100 + processing time) 
msec

асинхронный

NodeJs предлагает асинхронную функцию, которая по своей природе неблокирует, предположим, что в любой задаче ввода / вывода, которая требует времени (выборка, запись, чтение), nodejs не будет бездействовать и будет ждать завершения задачи, это ' Я начну выполнять следующие задачи в очереди, и всякий раз, когда эта задача будет завершена, она будет уведомлять об этом с помощью обратного вызова. Следующий пример поможет:

//Nodejs uses callback pattern to describe functions.
//Please read callback pattern to understand this example

//Suppose following function (I/O involved) took 500 msec
function timeConsumingFunction(params, callback){
  //GET DATA FROM SQL
  getDataFromSql(params, function(error, results){
    if(error){
      callback(error);
    }
    else{
      callback(null, results);
    }
  })
}

//Suppose following function is non-blocking and took 100 msec
function someOtherTask(){
  //some other task
  console.log('Some Task 1');
  console.log('Some Task 2');
}

console.log('Execution Start');

//Start With this function
timeConsumingFunction(params, function(error, results){
    if(error){
      console.log('Error')
    }
    else{
      console.log('Successfull'); 
    }
  })

//As (suppose) timeConsumingFunction took 500 msec, 
//As NodeJs is non-blocking, rather than remain idle for 500 msec, it will start 
//execute following function immediately
someOtherTask();

Короче говоря, вывод выглядит так:

Execution Start
//Roughly after 105 msec (5 msec it'll take in processing)
Some Task 1
Some Task 2
//Roughly After 510 msec
Error/Successful //depends on success and failure of DB function execution

Разница очевидна, когда синхронизация определенно займет более 600 (500 + 100 + время обработки) мс, асинхронность экономит время.


0

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

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

Оригинал Опубликовано на Github: Ссылка


0

Асинхронное программирование в JS:

синхронный

  • Останавливает выполнение следующего кода, пока это не будет сделано.
  • Поскольку это остановка дальнейшего выполнения, синхронный код называется «блокировкой». Блокировка в том смысле, что никакой другой код не будет выполнен.

Асинхронный

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

Пример:

// This function is synchronous
function log(arg) {
    console.log(arg)
}

log(1);

// This function is asynchronous
setTimeout(() => {
    console.log(2)
}, 0);

log(3)

  • Пример журналов 1, 3, 2.
  • 2 записывается последним, потому что он находится внутри асинхронной функции, которая выполняется после того, как стек пуст.
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.