Jaka jest różnica między programowaniem synchronicznym i asynchronicznym (w node.js)


189

Czytałem nodebeginner I natknąłem się na następujące dwa fragmenty kodu.

Pierwszy:

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

Drugie:

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

Rozumiem, co powinni zrobić, przeszukują bazę danych, aby uzyskać odpowiedź na zapytanie. A potem console.log('Hello world').

Pierwszy to rzekomo kod synchroniczny. A drugi to kod asynchroniczny.

Różnica między tymi dwoma kawałkami jest dla mnie bardzo niejasna. Jaki byłby wynik?

Googling w programowaniu asynchronicznym też mi nie pomógł.


41
Dziwne, że nic nie znalazłeś w google, to dość duży temat. W programowaniu synchronicznym każdy krok jest wykonywany jeden po zakończeniu wykonywania poprzedniego. W trybie asynchronicznym krok 2 zostanie wykonany, nawet jeśli krok 1 nie zostanie ukończony. Funkcja, którą widzisz zdefiniowana w drugim przykładzie, nazywa się funkcją callBack i zostanie uruchomiona, gdy tylko zostanie zwrócony wynik z bazy danych, co prawdopodobnie nastąpi po uruchomieniu pliku console.log.
Laurent S.

7
@Bartdude Było wiele na temat programowania asynchronicznego, ale nie było dość prostego wyjaśnienia, co to jest i co to znaczy w praktyce.
Azeirah

1
@GabrielLlamas Dlaczego powinniśmy unikać funkcji synchronicznych?
Charlie Parker,

3
@CharlieParker Ponieważ blokują pętlę zdarzeń, a Ty tracisz wszystkie korzyści z asynchronicznego modelu zdarzeń we / wy. A ponieważ to zła praktyka. Pomyśl o tym w ten sposób: Jeśli nie używasz funkcji asynchronicznych, dlaczego używasz Node.js?
Gabriel Llamas

1
@GabrielLlamas, jeśli wykonuję zapytanie INSERT i chcę później użyć ostatniego wstawionego identyfikatora database.query(), to powinienem wywołać je synchronicznie, prawda? lub jakie powinno być podejście? (To pytanie mam od dawna)
San

Odpowiedzi:


225

Różnica polega na tym, że w pierwszym przykładzie program zablokuje się w pierwszym wierszu. Następna linia ( console.log) będzie musiała poczekać.

w drugim przykładzie The console.logbędzie wykonane podczas zapytanie jest przetwarzany. Oznacza to, że zapytanie zostanie przetworzone w tle, podczas gdy twój program będzie robił inne rzeczy, a gdy dane zapytania będą gotowe, zrobisz z nim, co chcesz.

Krótko mówiąc: pierwszy przykład zostanie zablokowany, a drugi nie.

Dane wyjściowe następujących dwóch przykładów:

// 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");

Byłoby:

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

Uwaga
Chociaż sam węzeł jest jednowątkowy , istnieje kilka zadań, które można uruchomić równolegle. Na przykład operacje systemu plików występują w innym procesie.

Dlatego Node może wykonywać operacje asynchroniczne: jeden wątek wykonuje operacje na systemie plików, podczas gdy główny wątek Node wykonuje kod javascript. Na serwerze sterowanym zdarzeniami, takim jak Węzeł, wątek systemu plików powiadamia główny wątek węzła o określonych zdarzeniach, takich jak zakończenie, niepowodzenie lub postęp, wraz z wszelkimi danymi powiązanymi z tym zdarzeniem (np. Wynikiem zapytania do bazy danych lub błędu wiadomość), a główny wątek węzła decyduje, co zrobić z tymi danymi.

Więcej na ten temat możesz przeczytać tutaj: Jak działa jednowątkowy nieblokujący model IO w Node.js


9
Zasadniczo, kiedy wykonam pierwszy fragment kodu, zrobi on coś takiego request query.; 5 seconds later when the request is done; console.log:; gdy drugie wykonywane jednokrotnie: request query; console.log; work on the query;
Azeirah

1
@JohnGalt sql działa na innym wątku. Ale oczywiście zależy to od implementacji używanego sterownika SQL. Sterownik powinien odrodzić nowy wątek, połączyć się z mysql i uruchomić zapytanie. Po zakończeniu opublikuj wynik w kolejce zdarzeń , a Węzeł oddzwoni.
Salvatorelab

4
Czy w przykładzie asynchronicznym nie można wygenerować tego samego, co numer 1? Jak na przykład, database.querykończy się tak szybko, że zanim dotrzemy console.logzadanie jest już wykonane.
greatwolf,

2
@ TheBronx, jeśli console.log("Next line");w przykładzie 2 znajdował się w funkcji anonimowej, więc zaraz potem console.log("query finished");oznaczałoby to, że „Następna linia” zostanie wydrukowana PO zakończeniu zapytania, prawda? Więc jeśli mam wszystko w sposób zagnieżdżony, wszystko działałoby w sposób synchroniczny, więc nie musiałbym się martwić o używanie synchronicznych wersji niektórych funkcji. Czy mam rację w moim rozumieniu?
Abdul,

4
Krótka odpowiedź : Tak @Abdul, masz rację. Długa odpowiedź : zagnieżdżanie funkcji (oddzwanianie) to sposób na sekwencyjne wykonywanie czynności „jeden po drugim”. Ale technicznie nie jest to „synchroniczne”. Funkcja anonimowa jest nadal wykonywana „po zakończeniu operacji blokowania” lub innymi słowy „asynchronicznie”. Node.js może wykonywać inne funkcje podczas operacji blokowania. Funkcje pozostają asynchroniczne, po prostu je łączysz. Funkcje synchronizacji blokują wykonywanie, to jest klucz.
Salvatorelab,

75

Różnica między tymi dwoma podejściami jest następująca:

Sposób synchroniczny: czeka na zakończenie każdej operacji, po czym wykonuje tylko następną operację. W przypadku zapytania: console.log()polecenie nie zostanie wykonane, dopóki zapytanie nie zakończy się, aby uzyskać wszystkie wyniki z bazy danych.

Sposób asynchroniczny: nigdy nie czeka na zakończenie każdej operacji, raczej wykonuje wszystkie operacje tylko w pierwszym GO. Wynik każdej operacji zostanie obsłużony, gdy wynik będzie dostępny. W przypadku zapytania: console.log()polecenie zostanie wykonane wkrótce po Database.Query()metodzie. Podczas gdy zapytanie do bazy danych działa w tle i ładuje wynik po zakończeniu pobierania danych.

Przypadków użycia

  1. Jeśli twoje operacje nie wykonują bardzo ciężkich operacji podnoszenia, takich jak wysyłanie zapytań do ogromnych danych z DB, postępuj zgodnie z metodą Synchroniczną, inaczej Asynchroniczną.

  2. W sposób asynchroniczny możesz pokazać użytkownikowi wskaźnik postępu, a w tle możesz kontynuować ciężką pracę. Jest to idealny scenariusz dla aplikacji GUI.


2
Czy to oznacza, że ​​db.query (cmd, callback) działa jednocześnie (jak w wątkach)? Czy biegają w tym samym czasie?
Charlie Parker

Czy w jego drugim przykładzie istnieje szansa, że ​​zapytanie zakończy się tak szybko, że najpierw wywołuje funkcję zwrotną console.log?
Fahmi,

@Fahmi teoretycznie tak, praktycznie całkiem niemożliwe
Leo Messi

24

Stałoby się to nieco wyraźniejsze, jeśli dodasz wiersz do obu przykładów:

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

Drugie:

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

Spróbuj uruchomić je, a zauważysz, że pierwszy (synchroniczny) przykład, wynik. Długość zostanie wydrukowany PRZED linią „Hello World”. W drugim (asynchronicznym) przykładzie wynik. Długość zostanie (najprawdopodobniej) wydrukowany PO wierszu „Hello World”.

Dzieje się tak, ponieważ w drugim przykładzie database.queryjest on uruchamiany asynchronicznie w tle, a skrypt jest kontynuowany od razu z „Hello World”. console.log(result.length)Jest wykonywana tylko wtedy, gdy zapytanie do bazy danych została zakończona.


1
mówisz: wynik. długość zostanie (najprawdopodobniej) wydrukowana PO wierszu „Hello World”. .... dlaczego miałoby to być tylko „najbardziej prawdopodobne”? Myślę, że zawsze jest drukowany po wyjściu pliku console.log. Dzięki za wyjaśnienia :)
ludzkośćANDpeace

9
@humanityANDpeace: to cały punkt asynchronicznego dostępu: nie wiesz, kiedy to nastąpi. Być może jest to absurdalnie szybka baza danych, a zapytanie do bazy danych zwraca się jeszcze zanim Javascript dojdzie do wiersza „Hello World” ...
Martijn

19

Po pierwsze, zdaję sobie sprawę, że spóźniłem się z odpowiedzią na to pytanie.

Zanim omówimy synchroniczne i asynchroniczne, przyjrzyjmy się pokrótce, jak działają programy.

W przypadku synchronicznym każda instrukcja kończy się przed uruchomieniem następnej instrukcji. W takim przypadku program jest oceniany dokładnie w kolejności instrukcji.

Tak działa asynchroniczny w JavaScript. Mechanizm JavaScript składa się z dwóch części, z których jedna przegląda kod i kolejkuje operacje, a druga przetwarza kolejkę. Przetwarzanie kolejki odbywa się w jednym wątku, dlatego jednocześnie może wystąpić tylko jedna operacja.

Gdy widoczna jest operacja asynchroniczna (jak drugie zapytanie bazy danych), kod jest analizowany, a operacja umieszczana w kolejce, ale w tym przypadku rejestrowane jest wywołanie zwrotne do uruchomienia po zakończeniu tej operacji. W kolejce może być już wiele operacji. Operacja z przodu kolejki jest przetwarzana i usuwana z kolejki. Po przetworzeniu operacji na zapytanie do bazy danych żądanie jest wysyłane do bazy danych, a po zakończeniu wywołanie zwrotne zostanie wykonane po zakończeniu. W tej chwili procesor kolejek, który „obsłużył” operację, przechodzi do następnej operacji - w tym przypadku

    console.log("Hello World"); 

Zapytanie do bazy danych jest nadal przetwarzane, ale operacja console.log znajduje się z przodu kolejki i jest przetwarzana. Ta operacja synchroniczna jest wykonywana natychmiast, co powoduje natychmiastowe wyświetlenie wyniku „Hello World”. Jakiś czas później operacja bazy danych jest zakończona, dopiero wtedy wywołanie zwrotne zarejestrowane w zapytaniu jest wywoływane i przetwarzane, ustawiając wartość wyniku zmiennej na wiersze.

Możliwe, że jedna operacja asynchroniczna spowoduje kolejną operację asynchroniczną, ta druga operacja zostanie umieszczona w kolejce, a jeśli dojdzie do przodu kolejki, zostanie przetworzona. Wywołanie wywołania zwrotnego zarejestrowanego w operacji asynchronicznej jest sposobem, w jaki czas działania JavaScript zwraca wynik operacji po jej zakończeniu.

Prostą metodą sprawdzenia, która operacja JavaScript jest asynchroniczna, jest zwrócenie uwagi, czy wymaga ona wywołania zwrotnego - wywołanie zwrotne to kod, który zostanie wykonany po zakończeniu pierwszej operacji. W dwóch przykładach w pytaniu widzimy, że tylko drugi przypadek ma wywołanie zwrotne, więc jest to asynchroniczna operacja dwóch. Nie zawsze tak jest z powodu różnych stylów obsługi wyniku operacji asynchronicznej.

Aby dowiedzieć się więcej, przeczytaj o obietnicach. Obietnice to kolejny sposób, w jaki można obsłużyć wynik operacji asynchronicznej. Zaletą obietnic jest to, że styl kodowania przypomina bardziej kod synchroniczny.

Wiele bibliotek, takich jak węzeł „fs”, udostępnia style synchroniczne i asynchroniczne dla niektórych operacji. W przypadkach, gdy operacja nie trwa długo i nie jest często używana - jak w przypadku odczytu pliku konfiguracyjnego - operacja synchroniczna spowoduje, że kod będzie łatwiejszy do odczytania.


6

W przypadku synchronicznym polecenie console.log nie jest wykonywane, dopóki zapytanie SQL nie zakończy się.

W przypadku asynchronicznym polecenie console.log zostanie wykonane bezpośrednio. Wynik zapytania zostanie następnie zapisany przez funkcję „oddzwaniania”.


1
Ale czy faktycznie są wywoływani jednocześnie? To, co mnie dezorientuje, to to, że w kodzie asynchronicznym rzeczywisty kod jest uruchamiany jednocześnie w tym samym czasie?
Charlie Parker,

Zależy to od procesora (czy jest to procesor wielordzeniowy?) I systemu operacyjnego. Zobacz en.wikipedia.org/wiki/Multithreading_(software)#Multithreading
powiązane

4

Główna różnica polega na programowaniu asynchronicznym, w przeciwnym razie nie można zatrzymać wykonywania. Możesz kontynuować wykonywanie innego kodu podczas tworzenia „żądania”.


2

Ta funkcja sprawia, że ​​druga jest asynchroniczna.

Pierwszy zmusza program do czekania, aż każda linia zakończy działanie, zanim następny będzie mógł kontynuować. Drugi pozwala każdej linii biegać jednocześnie (i niezależnie) jednocześnie.

Języki i frameworki (js, node.js), które pozwalają na asynchronię lub współbieżność, świetnie nadają się do rzeczy wymagających transmisji w czasie rzeczywistym (np. Czat, aplikacje giełdowe).


0

Programowanie synchroniczne

Języki programowania, takie jak C, C #, Java są programowaniem synchronicznym, wszystko, co piszesz, będzie wykonywane w kolejności pisania.

-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

Asynchronizacja

NodeJs ma funkcję asynchroniczną, nie ma charakteru blokowania, załóżmy, że w każdym zadaniu we / wy, które wymaga czasu (pobieranie, pisanie, czytanie), nodejs nie będzie bezczynny i nie będzie czekał na zakończenie zadania, to „ Zacznę wykonywać kolejne zadania w kolejce i za każdym razem, gdy podejmowanie zadania zakończy się, powiadomi za pomocą wywołania zwrotnego. Poniższy przykład pomoże:

//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();

Krótko mówiąc, wynik jest następujący:

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

Różnica jest oczywista, gdzie synchronizacja z pewnością zajmie więcej niż 600 (500 + 100 + czas przetwarzania) ms, asynchronia oszczędza czas.


0

Funkcje synchroniczne blokują, a funkcje asynchroniczne nie. W funkcjach synchronicznych instrukcje kończą się przed uruchomieniem następnej instrukcji. W takim przypadku program jest oceniany dokładnie w kolejności instrukcji, a wykonywanie programu jest wstrzymywane, jeśli jedna z instrukcji zajmuje bardzo dużo czasu.

Funkcje asynchroniczne zwykle akceptują wywołanie zwrotne jako parametr i wykonywanie jest kontynuowane w następnym wierszu natychmiast po wywołaniu funkcji asynchronicznej. Wywołanie zwrotne jest wywoływane tylko wtedy, gdy operacja asynchroniczna jest zakończona, a stos wywołań jest pusty. Intensywne operacje, takie jak ładowanie danych z serwera WWW lub wyszukiwanie w bazie danych, powinny być wykonywane asynchronicznie, aby główny wątek mógł kontynuować wykonywanie innych operacji zamiast blokować do czasu zakończenia tej długiej operacji (w przypadku przeglądarek interfejs użytkownika zawiesza się) .

Orginal Wysłany na Github: Link


0

Programowanie asynchroniczne w JS:

Synchroniczny

  • Zatrzymuje wykonywanie dalszego kodu, dopóki nie zostanie to wykonane.
  • Ponieważ jest to zatrzymanie dalszego wykonywania, kod synchroniczny nazywa się „blokowaniem”. Blokowanie w tym sensie, że żaden inny kod nie zostanie wykonany.

Asynchroniczny

  • Wykonanie tego jest odroczone do pętli zdarzeń, jest to konstrukcja na maszynie wirtualnej JS, która wykonuje funkcje asynchroniczne (po pustym stosie funkcji synchronicznych).
  • Kod asynchroniczny nazywany jest nieblokującym, ponieważ nie blokuje dalszego działania kodu.

Przykład:

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

log(1);

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

log(3)

  • Przykładowe dzienniki 1, 3, 2.
  • 2 jest rejestrowane jako ostatnie, ponieważ znajduje się w funkcji asynchronicznej, która jest wykonywana po opróżnieniu stosu.
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.