同期プログラミングと非同期プログラミングの違いは何ですか(node.js内)


189

nodebeginnerを読んでい て、次の2つのコードに遭遇しました。

最初の1つ:

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

2つ目:

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

私は彼らがしなければならないことを取得し、彼らはデータベースにクエリを実行してクエリへの回答を取得します。そしてconsole.log('Hello world')

最初のものはおそらく同期コードです。2つ目は非同期コードです。

2つの部分の違いは私には非常にあいまいです。出力はどうなりますか?

非同期プログラミングでグーグルしても助けにはなりませんでした。


41
あなたがグーグルで何も見つけられなかったStange、それはかなり大きな主題です。同期プログラミングでは、各ステップは、前のステップの実行が終了した後に1つ実行されます。非同期では、ステップ1が完了していなくても、ステップ2が実行されます。2番目の例で定義されている関数は、callBack関数と呼ばれ、データベースからの結果が返されるとすぐに実行されます。これは、おそらくconsole.logが実行された後です。
Laurent S.

7
@Bartdude非同期プログラミングには多くのことがありましたが、それが何であるか、そして実際にはそれが何を意味するのかについて、いくらか単純な説明はありませんでした。
アゼイラ2013年

1
@GabrielLlamasなぜ同期関数を避ける必要があるのですか?
チャーリーパーカー

3
@CharlieParkerイベントループをブロックし、非同期イベントI / Oモデルのすべての利点を失うからです。そしてそれは悪い習慣だからです。このように考えてください:非同期関数を使用していないのに、なぜNode.jsを使用しているのですか?
ガブリエルラマ14

1
@ GabrielLlamas、INSERTクエリを実行していて、最後に挿入されたIDを後に使用したい場合、database.query()それを同期的に呼び出す必要がありますよね?またはアプローチはどうあるべきですか?(私は長い時間のために持っているこの質問)
サン

回答:


224

違いは、最初の例では、プログラムが最初の行でブロックすることです。次の行(console.log)は待機する必要があります。

第二の例console.logクエリが処理されている間に実行されます。つまり、プログラムが他のことを行っている間、クエリはバックグラウンドで処理され、クエリデータの準備ができたら、それを使用して必要なことをすべて実行します。

つまり、簡単に言うと、最初の例はブロックされますが、2番目の例はブロックされません。

次の2つの例の出力:

// 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自体はシングルスレッドですが、並行して実行できるタスクがいくつかあります。たとえば、ファイルシステム操作は別のプロセスで発生します。

ノードが非同期操作を実行できるのはそのためです。メインのノードスレッドがJavaScriptコードを実行している間、1つのスレッドがファイルシステム操作を実行しています。Nodeなどのイベント駆動型サーバーでは、ファイルシステムスレッドはメインノードスレッドに、完了、失敗、進行などの特定のイベントと、そのイベントに関連するデータ(データベースクエリやエラーの結果など)を通知しますメッセージ)とメインノードスレッドがそのデータをどう処理するかを決定します。

これについて詳しくは、こちらをご覧ください。Node.jsでのシングルスレッドの非ブロッキングIOモデルの仕組み


9
つまり、基本的に、最初のコードを実行すると、次のようになります request query.; 5 seconds later when the request is done; console.log。ときに、第2の1の実行: request query; console.log; work on the query;
アゼイラ2013年

1
@JohnGalt SQLは別のスレッドで実行されます。しかしもちろん、それは使用するSQLドライバの実装に依存します。ドライバは新しいスレッドを生成し、mysqlに接続してクエリを実行する必要があります。完了したら、結果をイベントキューに投稿すると、Nodeがコールバックを呼び出します。
Salvatorelab

4
非同期の例が#1と同じものを出力することは可能ではありませんか?たとえば、database.query非常に速く終了するためconsole.log、タスクに到達するまでにタスクはすでに完了しています。
greatwolf 2013年

2
@TheBronx console.log("Next line");は、例2が無名関数の内部にある場合、その直後にconsole.log("query finished");、「次の行」が「クエリが完了した」後に印刷されることを意味しますか?したがって、すべてを入れ子にした場合、すべてが同期して実行されるため、特定の関数の同期バージョンの使用について心配する必要はありません。私の理解は正しいですか?
Abdul

4
短い答え:はい@アブドゥル、あなたは正しい。長い答え:入れ子関数(コールバック)は、物事を「次々に」順番に実行する方法です。しかし、それは技術的には「同期」ではありません。匿名関数は、「ブロッキング操作が終了したとき」、つまり「非同期に」実行されます。Node.jsは、ブロッキング操作の実行中に他の機能を実行できます。関数は非同期のままですが、それらを連鎖させているだけです。同期機能は実行をブロックします。それが鍵です。
Salvatorelab

74

これら2つのアプローチの違いは次のとおりです。

同期方法: 各操作が完了するまで待機し、その後、次の操作のみを実行します。あなたのクエリのために:console.log()データベースからすべての結果を取得するクエリの実行が終了しない限り、コマンドは&まで実行されません。

非同期の方法: 各操作の完了を待たずに、最初のGOでのみすべての操作を実行します。各操作の結果は、結果が利用可能になると処理されます。クエリの場合:console.log()コマンドはDatabase.Query()メソッドのます。データベースクエリはバックグラウンドで実行され、データの取得が完了すると結果をロードします。

ユースケース

  1. オペレーションがDBからの巨大なデータのクエリのように非常に重い処理を行わない場合は、同期方法を使用します。

  2. 非同期の方法で、進行状況インジケーターをユーザーに表示しながら、バックグラウンドで重い作業を続行できます。これはGUIアプリの理想的なシナリオです。


2
それは、db.query(cmd、callback)が同時に(スレッドのように)実行されていることを意味しますか?それらは同時に実行されていますか?
チャーリーパーカー

彼の2番目の例では、クエリが非常に速く終了してから、コールバックを最初に呼び出す可能性はありますconsole.logか?
Fahmi、2016年

@Fahmiは理論的にはい、実際にはまったく不可能
Leo Messi

24

両方の例に行を追加すると、これはもう少し明確になります。

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

2つ目:

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

これらを実行してみると、最初の(同期)例であるresult.lengthが「Hello World」行の前に出力されることがわかります。2番目(非同期)の例では、result.lengthは(ほとんどの場合) "Hello World"行の後に出力されます。

これは、2番目の例では、database.queryがバックグラウンドで非同期に実行され、スクリプトが「Hello World」ですぐに続行するためです。console.log(result.length)データベースクエリが完了したときにのみ実行されます。


1
あなたが言う:result.lengthは(おそらく) "Hello World"行の後に出力されます。....なぜそれが「最も可能性が高い」だけなのでしょうか?常にconsole.log出力の後に出力されると思います。説明をありがとう:)
humanityANDpeace 14年

9
@humanityANDpeace:これが非同期アクセスの要点です。いつ実行されるかはわかりません。おそらく、それはとてつもなく速いデータベースであり、Javascriptが「Hello World」の行に到達する前でも、データベースクエリが返されます...
Martijn

19

最初に、私はこの質問に答えるのが遅いことに気づきました。

同期と非同期について説明する前に、プログラムの実行方法について簡単に説明します。

では、同期の場合、各ステートメントの完了、次のステートメントが実行される前に。この場合、プログラムはステートメントの順序で正確に評価されます。

これは非同期です、JavaScriptで機能するです。JavaScriptエンジンには2つの部分があります。1つはコードを調べて操作をエンキューする部分で、もう1つはキューを処理します。キューの処理は1つのスレッドで行われるため、一度に1つの操作しか実行できません。

非同期操作(2番目のデータベースクエリなど)が見られると、コードが解析されて操作がキューに入れられますが、この場合、この操作が完了すると実行されるようにコールバックが登録されます。キューにはすでに多くの操作が含まれている可能性があります。キューの先頭にある操作が処理され、キューから削除されます。データベースクエリの操作が処理されると、リクエストがデータベースに送信され、完了すると、完了時にコールバックが実行されます。この時点で、操作を「処理」したキュープロセッサは次の操作に移ります-この場合

    console.log("Hello World"); 

データベースクエリはまだ処理中ですが、console.log操作はキューの先頭にあり、処理されます。これは同期操作であるため、すぐに実行され、すぐに「Hello World」という出力が生成されます。しばらくして、データベース操作が完了します。その後、クエリに登録されたコールバックが呼び出されて処理され、変数の結果の値が行に設定されます。

1つの非同期操作で別の非同期操作が発生する可能性があります。この2番目の操作はキューに入れられ、キューの先頭に来ると処理されます。非同期操作で登録されたコールバックの呼び出しは、JavaScriptランタイムが操作の完了時に操作の結果を返す方法です。

どのJavaScript操作が非同期であるかを知る簡単な方法は、コールバックが必要かどうかを確認することです。コールバックは、最初の操作が完了したときに実行されるコードです。問題の2つの例では、2番目のケースにのみコールバックがあることがわかります。したがって、これは2つの非同期操作です。非同期操作の結果を処理するスタイルが異なるため、常にそうであるとは限りません。

詳細については、約束をお読みください。Promiseは、非同期操作の結果を処理できるもう1つの方法です。promiseの良い点は、コーディングスタイルが同期コードに似ていることです。

ノード 'fs'のような多くのライブラリは、いくつかの操作に対して同期と非同期の両方のスタイルを提供します。操作に時間がかからず、頻繁に使用されない場合(構成ファイルを読み取る場合など)は、同期スタイルの操作により、コードが読みやすくなります。


6

同期の場合、SQLクエリの実行が完了するまで、console.logコマンドは実行されません。

非同期の場合、console.logコマンドは直接実行されます。クエリの結果は、後で「コールバック」関数によって格納されます。


1
しかし、実際には同時に呼び出されていますか?私を混乱させるのは、非同期コードで、実際のコードが同時に並行して実行されているのですか?
チャーリーパーカー

これは、プロセッサ(マルチコアですか?)とオペレーティングシステムによって異なります。en.wikipedia.org/wiki/Multithreading_(software)#Multithreading
関連する

4

主な違いは非同期プログラミングです。それ以外の場合は実行を停止しません。「リクエスト」が行われている間、他のコードの実行を続けることができます。


2

この関数は、2番目のものを非同期にします。

最初のものはプログラムに、各行が実行を完了するのを待ってから、次の行が続行できるようにします。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は非同期機能を備えており、本質的に非ブロッキングです。時間(フェッチ、書き込み、読み取り)がかかるI / Oタスクでは、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

同期関数はブロックしていますが、非同期関数はブロックしていません。同期関数では、ステートメントは次のステートメントが実行される前に完了します。この場合、プログラムはステートメントの順序で正確に評価され、ステートメントの1つに非常に長い時間がかかる場合、プログラムの実行は一時停止されます。

非同期関数は通常、コールバックをパラメーターとして受け入れ、非同期関数が呼び出された直後に次の行で実行が続行されます。コールバックは、非同期操作が完了し、呼び出しスタックが空の場合にのみ呼び出されます。Webサーバーからのデータのロードやデータベースのクエリなどのヘビーデューティー操作は非同期で実行する必要があるため、メインスレッドは、長い操作が完了するまでブロックせずに、他の操作の実行を続行できます(ブラウザーの場合、UIはフリーズします)。 。

オリジナルは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は、スタックが空になった後に実行される非同期関数内にあるため、最後にログに記録されます。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.