Was ist der Unterschied zwischen synchroner und asynchroner Programmierung (in node.js)


189

Ich habe Nodebeginner gelesen und bin auf die folgenden zwei Codeteile gestoßen .

Der erste:

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

Der zweite:

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

Ich bekomme, was sie tun sollen, sie fragen die Datenbank ab, um die Antwort auf die Anfrage abzurufen. Und dann console.log('Hello world').

Der erste ist angeblich synchroner Code. Und der zweite ist asynchroner Code.

Der Unterschied zwischen den beiden Stücken ist für mich sehr vage. Was wäre die Ausgabe?

Das Googeln über asynchrone Programmierung hat mir auch nicht geholfen.


41
Seltsam, dass Sie mit Google nichts gefunden haben, es ist ein ziemlich großes Thema. Bei der synchronen Programmierung wird jeder Schritt nach dem Ausführen des vorherigen Schrittes ausgeführt. In asynchronem Zustand wird Schritt 2 ausgeführt, auch wenn Schritt 1 nicht abgeschlossen ist. Die in Ihrem zweiten Beispiel definierte Funktion wird als callBack-Funktion bezeichnet und ausgeführt, sobald das Ergebnis aus der Datenbank zurückgegeben wird, wahrscheinlich nachdem das console.log ausgeführt wurde.
Laurent S.

7
@Bartdude Es gab viel über asynchrone Programmierung, aber keine etwas einfache Erklärung, was es ist und was es in der Praxis bedeutet.
Azeirah

1
@GabrielLlamas Warum sollten wir synchrone Funktionen vermeiden?
Charlie Parker

3
@CharlieParker Weil sie die Ereignisschleife blockieren und Sie alle Vorteile eines asynchronen E / A-Ereignismodells verlieren. Und weil es eine schlechte Praxis ist. Stellen Sie sich das so vor: Wenn Sie keine asynchronen Funktionen verwenden, warum verwenden Sie Node.js?
Gabriel Llamas

1
@GabrielLlamas, wenn ich eine INSERT-Abfrage ausführe und danach die zuletzt eingefügte ID verwenden möchte, database.query()sollte ich sie synchron aufrufen, oder? oder was sollte der Ansatz sein? (Diese Frage habe ich schon lange)
San

Antworten:


224

Der Unterschied besteht darin, dass im ersten Beispiel das Programm in der ersten Zeile blockiert. Die nächste Zeile ( console.log) muss warten.

Im zweiten Beispielconsole.log wird das ausgeführt , während die Abfrage verarbeitet wird. Das heißt, die Abfrage wird im Hintergrund verarbeitet, während Ihr Programm andere Aufgaben ausführt. Sobald die Abfragedaten fertig sind, können Sie damit tun, was Sie wollen.

Kurz gesagt: Das erste Beispiel wird blockieren, das zweite nicht.

Die Ausgabe der folgenden zwei Beispiele:

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

Wäre:

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

Hinweis
Während der Knoten selbst Single-Threaded ist , gibt es einige Aufgaben, die parallel ausgeführt werden können. Beispielsweise treten Dateisystemvorgänge in einem anderen Prozess auf.

Aus diesem Grund kann Node asynchrone Operationen ausführen: Ein Thread führt Dateisystemoperationen aus, während der Hauptknotenthread weiterhin Ihren Javascript-Code ausführt. In einem ereignisgesteuerten Server wie Node benachrichtigt der Dateisystem-Thread den Hauptknotenthread über bestimmte Ereignisse wie Abschluss, Fehler oder Fortschritt sowie über alle mit diesem Ereignis verbundenen Daten (z. B. das Ergebnis einer Datenbankabfrage oder eines Fehlers) message) und der Hauptknotenthread entscheidet, was mit diesen Daten geschehen soll.

Weitere Informationen hierzu finden Sie hier: Funktionsweise des nicht blockierenden E / A-Modells mit einem Thread in Node.js.


9
Wenn ich also den ersten Code ausführe, wird er ungefähr so ​​aussehen : request query.; 5 seconds later when the request is done; console.log; wenn der zweite ausgeführt wird : request query; console.log; work on the query;
Azeirah

1
@ JohnGalt die SQL läuft auf einem anderen Thread. Dies hängt natürlich von der Implementierung des von Ihnen verwendeten SQL-Treibers ab. Der Treiber sollte einen neuen Thread erzeugen, eine Verbindung zu MySQL herstellen und die Abfrage ausführen. Wenn Sie fertig sind, stellen Sie das Ergebnis in die Ereigniswarteschlange , und Node ruft den Rückruf auf.
Salvatorelab

4
Ist es nicht möglich, dass das asynchrone Beispiel dasselbe wie # 1 ausgibt? Wie zum Beispiel, database.queryendet so schnell, dass console.logdie Aufgabe bereits erledigt ist, wenn wir sie erreichen .
Urwolf

2
@TheBronx Wenn sich console.log("Next line");in Beispiel 2 die anonyme Funktion befindet, console.log("query finished");würde dies bedeuten, dass "Nächste Zeile" NACH "Abfrage beendet" gedruckt wird, oder? Wenn ich also alles verschachtelt habe, läuft alles synchron, sodass ich mir keine Gedanken über die Verwendung synchroner Versionen bestimmter Funktionen machen muss. Bin ich in meinem Verständnis richtig?
Abdul

4
Kurze Antwort : Ja @Abdul, du hast recht. Lange Antwort : Verschachtelungsfunktionen (Rückrufe) sind die Möglichkeit, Dinge nacheinander "nacheinander" auszuführen. Das ist aber technisch nicht "synchron". Die anonyme Funktion wird weiterhin "nach Beendigung des Blockiervorgangs" oder mit anderen Worten "asynchron" ausgeführt. Node.js könnte andere Funktionen ausführen, während diese Blockierungsoperation stattfindet. Funktionen bleiben asynchron, nur dass Sie sie verketten. Synchronisierungsfunktionen blockieren die Ausführung, das ist der Schlüssel.
Salvatorelab

74

Der Unterschied zwischen diesen beiden Ansätzen ist wie folgt:

Synchroner Weg: Es wartet, bis jeder Vorgang abgeschlossen ist, danach führt nur der nächste Vorgang aus. Für Ihre Abfrage: Der console.log()Befehl wird erst ausgeführt, wenn & die Ausführung der Abfrage abgeschlossen ist, um das gesamte Ergebnis aus der Datenbank abzurufen.

Asynchroner Weg: Es wartet nie auf den Abschluss jeder Operation, sondern führt alle Operationen nur im ersten GO aus. Das Ergebnis jeder Operation wird verarbeitet, sobald das Ergebnis verfügbar ist. Für Ihre Anfrage: Der console.log()Befehl wird kurz nach der Database.Query()Methode ausgeführt. Während die Datenbankabfrage im Hintergrund ausgeführt wird und das Ergebnis lädt, sobald der Abruf der Daten abgeschlossen ist.

Anwendungsfälle

  1. Wenn Ihre Vorgänge nicht sehr schwer sind, wie das Abfragen großer Datenmengen aus der Datenbank, fahren Sie mit der synchronen Methode fort, andernfalls mit der asynchronen Methode.

  2. Auf asynchrone Weise können Sie dem Benutzer eine Fortschrittsanzeige anzeigen, während Sie im Hintergrund mit Ihren schweren Arbeiten fortfahren können. Dies ist ein ideales Szenario für GUI-Apps.


2
Bedeutet das, dass db.query (cmd, callback) gleichzeitig ausgeführt wird (wie in Threads)? Laufen sie gleichzeitig?
Charlie Parker

Gibt es in seinem zweiten Beispiel eine Chance, dass die Abfrage so schnell beendet wird, dass sie dann zuerst den Rückruf aufruft console.log?
Fahmi

@ Rahmi theoretisch ja, praktisch unmöglich
Leo Messi

24

Dies wird etwas deutlicher, wenn Sie beiden Beispielen eine Zeile hinzufügen:

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

Der zweite:

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

Wenn Sie diese ausführen, werden Sie feststellen, dass das erste (synchrone) Beispiel, die result.length, VOR der Zeile "Hello World" ausgedruckt wird. Im zweiten (asynchronen) Beispiel wird die result.length (höchstwahrscheinlich) NACH der Zeile "Hello World" gedruckt.

Das liegt daran, dass im zweiten Beispiel das database.queryasynchron im Hintergrund ausgeführt wird und das Skript sofort mit der "Hallo Welt" fortgesetzt wird. Das console.log(result.length)wird nur ausgeführt, wenn die Datenbankabfrage abgeschlossen ist.


1
Sie sagen: Die result.length wird (höchstwahrscheinlich) NACH der Zeile "Hello World" gedruckt. .... warum sollte das nur "höchstwahrscheinlich" sein? Ich denke, es wird immer nach der Ausgabe von console.log gedruckt. Vielen Dank für die Klarstellung :)
Menschheit und

9
@humanityANDpeace: Das ist der gesamte Punkt des asynchronen Zugriffs: Sie wissen nicht, wann dies geschehen wird. Vielleicht ist es eine absurd schnelle Datenbank, und die Datenbankabfrage kehrt zurück, noch bevor Javascript die Zeile "Hallo Welt" erreicht ...
Martijn

19

Zuerst stelle ich fest, dass ich diese Frage zu spät beantworte.

Bevor wir uns mit synchron und asynchron befassen, wollen wir uns kurz ansehen, wie Programme ausgeführt werden.

Im synchronen Fall wird jede Anweisung abgeschlossen, bevor die nächste Anweisung ausgeführt wird. In diesem Fall wird das Programm genau in der Reihenfolge der Anweisungen ausgewertet.

So funktioniert Asynchron in JavaScript. Die JavaScript-Engine besteht aus zwei Teilen, einem Teil, der sich mit den Code- und Warteschlangenoperationen befasst, und einem anderen Teil, der die Warteschlange verarbeitet. Die Warteschlangenverarbeitung erfolgt in einem Thread. Daher kann jeweils nur eine Operation ausgeführt werden.

Wenn eine asynchrone Operation (wie die zweite Datenbankabfrage) angezeigt wird, wird der Code analysiert und die Operation in die Warteschlange gestellt. In diesem Fall wird jedoch ein Rückruf registriert, der ausgeführt werden soll, wenn diese Operation abgeschlossen ist. Die Warteschlange enthält möglicherweise bereits viele Vorgänge. Der Vorgang an der Vorderseite der Warteschlange wird verarbeitet und aus der Warteschlange entfernt. Sobald der Vorgang für die Datenbankabfrage verarbeitet wurde, wird die Anforderung an die Datenbank gesendet, und wenn der Rückruf abgeschlossen ist, wird er nach Abschluss ausgeführt. Zu diesem Zeitpunkt bewegt sich der Warteschlangenprozessor, der die Operation "behandelt" hat, zur nächsten Operation - in diesem Fall

    console.log("Hello World"); 

Die Datenbankabfrage wird noch verarbeitet, aber die Operation console.log befindet sich vorne in der Warteschlange und wird verarbeitet. Dies ist eine synchrone Operation, die sofort ausgeführt wird und sofort zur Ausgabe "Hello World" führt. Einige Zeit später wird der Datenbankvorgang abgeschlossen. Erst dann wird der bei der Abfrage registrierte Rückruf aufgerufen und verarbeitet, wobei der Wert des Variablenergebnisses auf Zeilen gesetzt wird.

Es ist möglich, dass eine asynchrone Operation zu einer anderen asynchronen Operation führt. Diese zweite Operation wird in die Warteschlange gestellt und an der Vorderseite der Warteschlange verarbeitet. Durch Aufrufen des bei einer asynchronen Operation registrierten Rückrufs gibt die JavaScript-Laufzeit das Ergebnis der Operation zurück, wenn sie abgeschlossen ist.

Eine einfache Methode, um zu wissen, welche JavaScript-Operation asynchron ist, besteht darin, festzustellen, ob ein Rückruf erforderlich ist. Der Rückruf ist der Code, der ausgeführt wird, wenn die erste Operation abgeschlossen ist. In den beiden Beispielen in der Frage können wir sehen, dass nur der zweite Fall einen Rückruf hat, also ist es die asynchrone Operation der beiden. Dies ist aufgrund der unterschiedlichen Arten der Behandlung des Ergebnisses einer asynchronen Operation nicht immer der Fall.

Um mehr zu erfahren, lesen Sie über Versprechen. Versprechen sind eine weitere Möglichkeit, mit dem Ergebnis einer asynchronen Operation umzugehen. Das Schöne an Versprechungen ist, dass sich der Codierungsstil eher wie synchroner Code anfühlt.

Viele Bibliotheken wie der Knoten 'fs' bieten für einige Operationen sowohl synchrone als auch asynchrone Stile. In Fällen, in denen die Operation nicht lange dauert und nicht häufig verwendet wird - wie beim Lesen einer Konfigurationsdatei - führt die Operation im synchronen Stil zu Code, der leichter zu lesen ist.


6

Im synchronen Fall wird der Befehl console.log erst ausgeführt, wenn die Ausführung der SQL-Abfrage abgeschlossen ist.

Im asynchronen Fall wird der Befehl console.log direkt ausgeführt. Das Ergebnis der Abfrage wird dann einige Zeit später von der "Rückruf" -Funktion gespeichert.


1
Aber werden die tatsächlich gleichzeitig gerufen? Was mich verwirrt, ist, dass im asynchronen Code der eigentliche Code gleichzeitig parallel ausgeführt wird.
Charlie Parker

Dies hängt vom Prozessor (ist es Multi-Core?) Und vom Betriebssystem ab. Siehe en.wikipedia.org/wiki/Multithreading_(software)#Multithreading
verwandte

4

Der Hauptunterschied besteht in der asynchronen Programmierung. Andernfalls beenden Sie die Ausführung nicht. Sie können weiterhin anderen Code ausführen, während die 'Anfrage' gestellt wird.


2

Die Funktion macht die zweite asynchron.

Der erste zwingt das Programm, zu warten, bis jede Zeile beendet ist, bevor die nächste fortgesetzt werden kann. Mit der zweiten Zeile kann jede Zeile gleichzeitig (und unabhängig) ausgeführt werden.

Sprachen und Frameworks (js, node.js), die Asynchronität oder Parallelität ermöglichen, eignen sich hervorragend für Dinge, die eine Echtzeitübertragung erfordern (z. B. Chat, Aktienanwendungen).


0

Programmierung synchronisieren

Programmiersprachen wie C, C #, Java sind Synchronisierungsprogramme. Was auch immer Sie schreiben, wird in der Reihenfolge Ihres Schreibens ausgeführt.

-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

Async

NodeJs bietet eine asynchrone Funktion, die nicht blockierend ist. Angenommen, bei jeder E / A-Aufgabe, die Zeit in Anspruch nimmt (Abrufen, Schreiben, Lesen), werden NodeJs nicht im Leerlauf gehalten und warten, bis die Aufgabe abgeschlossen ist. Ich beginne mit der Ausführung der nächsten Aufgaben in der Warteschlange. Sobald diese Aufgabe erledigt ist, wird dies per Rückruf benachrichtigt. Das folgende Beispiel hilft:

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

Kurz gesagt, die Ausgabe lautet wie folgt:

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

Der Unterschied ist klar, wo die Synchronisierung definitiv mehr als 600 (500 + 100 + Verarbeitungszeit) ms dauert. Asynchrone spart Zeit.


0

Synchrone Funktionen blockieren, asynchrone Funktionen nicht. In synchronen Funktionen werden Anweisungen abgeschlossen, bevor die nächste Anweisung ausgeführt wird. In diesem Fall wird das Programm genau in der Reihenfolge der Anweisungen ausgewertet und die Ausführung des Programms wird angehalten, wenn eine der Anweisungen sehr lange dauert.

Asynchrone Funktionen akzeptieren normalerweise einen Rückruf als Parameter und die Ausführung wird in der nächsten Zeile unmittelbar nach dem Aufrufen der asynchronen Funktion fortgesetzt. Der Rückruf wird nur aufgerufen, wenn der asynchrone Vorgang abgeschlossen ist und der Aufrufstapel leer ist. Hochleistungsvorgänge wie das Laden von Daten von einem Webserver oder das Abfragen einer Datenbank sollten asynchron ausgeführt werden, damit der Hauptthread weiterhin andere Vorgänge ausführen kann, anstatt zu blockieren, bis dieser lange Vorgang abgeschlossen ist (im Fall von Browsern friert die Benutzeroberfläche ein). .

Orginal Gepostet auf Github: Link


0

Asynchrone Programmierung in JS:

Synchron

  • Stoppt die Ausführung von weiterem Code, bis dies erledigt ist.
  • Aufgrund dieser Unterbrechung der weiteren Ausführung wird synchroner Code als "Blockieren" bezeichnet. Blockieren in dem Sinne, dass kein anderer Code ausgeführt wird.

Asynchron

  • Die Ausführung wird auf die Ereignisschleife verschoben. Dies ist ein Konstrukt in einer virtuellen JS-Maschine, die asynchrone Funktionen ausführt (nachdem der Stapel synchroner Funktionen leer ist).
  • Asynchroner Code wird als nicht blockierend bezeichnet, da er die Ausführung von weiterem Code nicht blockiert.

Beispiel:

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

log(1);

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

log(3)

  • Das Beispiel protokolliert 1, 3, 2.
  • 2 wird zuletzt protokolliert, da es sich in einer asynchronen Funktion befindet, die ausgeführt wird, nachdem der Stapel leer ist.
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.