イベントループについて


135

私はそれについて考えています、そしてこれは私が思いついたものです:

次のようなコードがあるとします。

console.clear();
console.log("a");
setTimeout(function(){console.log("b");},1000);
console.log("c");
setTimeout(function(){console.log("d");},0);

リクエストが届き、JSエンジンは上記のコードの実行を段階的に開始します。最初の2つの呼び出しは同期呼び出しです。しかし、setTimeoutメソッドに関しては、非同期実行になります。しかし、JSはすぐにそれから戻って、実行を継続する、と呼ばれていますNon-BlockingAsync。そしてそれは他にも取り組んでいます。

この実行の結果は次のとおりです。

acdb

つまり、基本的には2番目setTimeoutが最初に終了し、そのコールバック関数は最初のものよりも早く実行され、それは理にかなっています。

ここではシングルスレッドアプリケーションについて説明します。JS Engineはこれを実行し続け、最初のリクエストが終了しない限り、2番目のリクエストには進みません。しかし良い点は、setTimeout解決するようなブロック操作を待たないため、新しい着信要求を受け入れるため、処理が速くなることです。

しかし、私の質問は次の項目に関して発生します。

#1:シングルスレッドアプリケーションについて話している場合setTimeouts、JSエンジンがより多くのリクエストを受け入れて実行する間に、どのメカニズムが処理しますか?シングルスレッドは他のリクエストに対してどのように機能し続けますか?何が上で動作しsetTimeout、他の要求がでてくると実行を取得しています。

#2:これらのsetTimeout関数がバックグラウンドで実行され、さらに多くのリクエストが入って実行されている場合、バックグラウンドで非同期実行を実行するものは何ですか?私たちが話しているこのことは何と呼ばれていEventLoopますか?

#3:しかし、メソッド全体をに入れEventLoopて、全体が実行され、コールバックメソッドが呼び出されるようにしないでください。これは、コールバック関数について話すときに理解できることです。

function downloadFile(filePath, callback)
{
  blah.downloadFile(filePath);
  callback();
}

しかし、この場合、JSエンジンは非同期関数であるかどうかをどのようにして認識し、コールバックEventLoop? Perhaps something like theをC#のasync`キーワードに入れるか、JSエンジンが行うメソッドが非同期メソッドであることを示す何らかの属性を置くことができます。それに応じて処理する必要があります。

#4:しかし、記事は、物事がどのように機能しているのかについて私が推測していたこととはまったく逆のことを言っています。

イベントループは、コールバック関数のキューです。非同期関数が実行されると、コールバック関数がキューにプッシュされます。JavaScriptエンジンは、非同期関数が実行された後のコードが実行されるまで、イベントループの処理を開始しません。

#5:この画像は参考になるかもしれませんが、画像の最初の説明は、質問番号4で述べたものとまったく同じことを言っています。

ここに画像の説明を入力してください

だから私の質問は、上記の項目についていくつかの説明を得ることですか?


1
スレッドは、これらの問題を処理するための適切なメタファーではありません。イベントを考えてください。
DenysSéguret2014

1
@dystroy:JSのイベントメタファーがよくわかるコードサンプル。
Tarik

ここであなたの質問が正確に何であるかわかりません。
DenysSéguret2014

1
@dystroy:ここに私の質問は、上記の項目についていくつかの説明を取得することですか?
Tarik

2
ノードはシングルスレッドではありませんが、それはあなたには関係ありません(ユーザーコードの実行中にノードが他のことを実行できるという事実は別です)。ユーザーコードでは、一度に1つのコールバックのみが実行されます。
DenysSéguret2014

回答:


85

1:シングルスレッドアプリケーションについて話している場合、JSエンジンがより多くのリクエストを受け入れて実行する間に、setTimeoutsを処理するのは何ですか?その単一のスレッドは他のリクエストで引き続き動作しませんか?次に、他のリクエストが来て実行され続ける間、誰がsetTimeoutに取り組み続けるのでしょう。

実際にプログラムのJavaScriptを実行するノードプロセスには1つのスレッドしかありません。ただし、ノード自体の内部には、実際にはイベントループメカニズムの操作を処理するいくつかのスレッドがあり、これにはIOスレッドのプールと他の少数のスレッドが含まれます。重要なのは、これらのスレッドの数が、接続ごとのスレッドの同時実行モデルの場合のように処理される同時接続の数に対応していないことです。

ここで、「setTimeoutsの実行」について、を呼び出すとsetTimeout、すべてのノードが行うことは基本的に、将来一度に実行される関数のデータ構造を更新することだけです。基本的に、実行する必要のある一連のキューがあり、イベントループのすべての「ティック」が1つを選択し、それをキューから削除して実行します。

理解しておくべき重要なことは、ノードは重い作業のほとんどをOSに依存しているということです。そのため、着信ネットワーク要求は実際にはOS自体によって追跡され、ノードが処理する準備ができると、システムコールを使用して、処理可能なデータを含むネットワーク要求をOSに要求します。IOの「作業」ノードの多くは、「ちょっとOS、データを読み取る準備ができたネットワーク接続を取得しましたか?」または「ちょっとOS、私の未解決のファイルシステム呼び出しのいずれかでデータの準備ができていますか?」内部アルゴリズムとイベントループエンジンの設計に基づいて、ノードは実行するJavaScriptの「ティック」を1つ選択して実行し、プロセスをもう一度繰り返します。それがイベントループの意味です。Nodeは基本的に常に「次に実行する必要があるJavaScriptの少しは何か」を決定し、それを実行します。setTimeoutまたはprocess.nextTick

2:これらのsetTimeoutがバックグラウンドで実行され、さらに多くのリクエストが出入りして実行されている場合、バックグラウンドで非同期実行を実行するのは、EventLoopについて話しているものです。

JavaScriptがバックグラウンドで実行されることはありません。プログラム内のすべてのJavaScriptは、一度に1つずつ前と中央で実行されます。バックグラウンドで行われるのは、OSがIOを処理し、ノードがIOの準備ができるまで待機し、ノードが実行を待機するJavaScriptのキューを管理することです。

3:JS Engineは、EventLoopに配置できるように、それが非同期関数であるかどうかをどのようにして知ることができますか?

ノードコアには、システムコールを行い、OSまたはC ++を呼び出さなければならないためノードがこれらを認識しているため、非同期の固定関数セットがあります。基本的に、すべてのネットワークおよびファイルシステムIOと子プロセスの相互作用は非同期であり、JavaScriptがノードに非同期で何かを実行させる唯一の方法は、ノードコアライブラリによって提供される非同期関数の1つを呼び出すことです。独自のAPIを定義するnpmパッケージを使用している場合でも、イベントループを生成するために、最終的にそのnpmパッケージのコードはノードコアの非同期関数の1つを呼び出します。これは、ティックが完了し、イベントを開始できることをノードが知ったときです。ループアルゴリズムを再度。

4イベントループは、コールバック関数のキューです。非同期関数が実行されると、コールバック関数がキューにプッシュされます。JavaScriptエンジンは、非同期関数が実行された後のコードが実行されるまで、イベントループの処理を開始しません。

はい、これは本当ですが、誤解を招く恐れがあります。重要なことは、通常のパターンは次のとおりです。

//Let's say this code is running in tick 1
fs.readFile("/home/barney/colors.txt", function (error, data) {
  //The code inside this callback function will absolutely NOT run in tick 1
  //It will run in some tick >= 2
});
//This code will absolutely also run in tick 1
//HOWEVER, typically there's not much else to do here,
//so at some point soon after queueing up some async IO, this tick
//will have nothing useful to do so it will just end because the IO result
//is necessary before anything useful can be done

つまり、メモリ内のすべてのフィボナッチ数を同じティックで同期的にカウントするだけで、イベントループを完全にブロックできます。そうすれば、プログラムが完全にフリーズします。それは協調的並行性です。JavaScriptのティックごとに、ある程度の時間内にイベントループを生成する必要があります。そうしないと、アーキテクチャ全体が失敗します。


1
サーバーの実行に1分かかるキューがあるとします。最初のことは、10秒後に終了する非同期関数でした。それはキューの最後に行きますか、それとも準備ができた瞬間に自分自身をラインに押し込みますか?
ilyo 2014

4
通常はキューの最後に移動しますが、process.nextTickvs setTimeoutvs のセマンティクスsetImmediateは微妙に異なりますが、実際には気にする必要はありません。私が持っているのsetTimeoutや友人と呼ばれるブログ記事の詳細に入ります。
Peter Lyons 2014

詳しく説明していただけますか?2つのコールバックがあり、最初のコールバックには10mSの実行時間とsetTimeoutが1分のchangeColorメソッドがあり、2番目のコールバックには50msの実行時間とsetTimeoutが10秒のchangeBackgroundメソッドがあるとします。changeBackgroundは最初にQueueにあり、changeColorは次になります。その後、イベントループはメソッドを同期的に選択します。私は正しいですか?
SheshPai 2015

1
@SheshPai英語の段落で書かれたコードを議論するのは誰にとっても混乱しすぎです。コードスニペットを使用して新しい質問を投稿するだけで、コードの説明ではなくコードに基づいて回答できるようになり、あいまいさが多く残ります。
Peter Lyons

youtube.com/watch?v=QyUFheng6J0&spfreload=5これは、JavaScriptエンジンのもう1つの良い説明です
Mukesh Kumar

65

フィリップロバーツによる素晴らしいビデオチュートリアルがあり、javascriptイベントループを最も単純かつ概念的な方法で説明しています。すべてのJavaScript開発者は一見する必要があります。

こちらはYoutube のビデオリンクです。


16
私はそれを見て、それは確かにこれまでで最高の説明でした。
Tarik

1
JavaScriptのファンと愛好家のためのビデオを見る必要があります。
Nirus 2017

1
このビデオは私のライブを変えます^^
HuyTran

1
ここをさまよいました..これは私が得た最高の説明の1つです。共有してくれてありがとう...:D
RohitS

1
それは目を見張るものでした
HebleV

11

ホストプロセスがシングルスレッドであるとは考えないでください。シングルスレッドではありません。シングルスレッドとは、JavaScriptコードを実行するホストプロセスの部分です。

バックグラウンドワーカーを除いて、これらはシナリオを複雑にします...

したがって、すべてのjsコードは同じスレッドで実行され、jsコードの2つの異なる部分が同時に実行される可能性はありません(したがって、並行処理の管理ができません)。

実行中のjsコードは、ホストプロセスがイベントループから取得した最後のコードです。コードでは、基本的に2つのことを実行できます。同期命令を実行することと、いくつかのイベントが発生したときに将来実行されるように関数をスケジュールすることです。

ここにあなたのサンプルコードの私の精神的な表現があります(注意:それはそれだけです、私はブラウザ実装の詳細がわかりません!):

console.clear();                                   //exec sync
console.log("a");                                  //exec sync
setTimeout(                //schedule inAWhile to be executed at now +1 s 
    function inAWhile(){
        console.log("b");
    },1000);    
console.log("c");                                  //exec sync
setTimeout(
    function justNow(){          //schedule justNow to be executed just now
        console.log("d");
},0);       

コードの実行中、ホストプロセスの別のスレッドが、発生しているすべてのシステムイベント(UIのクリック、ファイルの読み取り、受信したネットワークパケットなど)を追跡します。

コードが完了すると、イベントループから削除され、ホストプロセスはコードのチェックに戻り、実行するコードがまだあるかどうかを確認します。イベントループにはさらに2つのイベントハンドラーが含まれています。1つは現在実行される(justNow関数)、もう1つは1秒以内に実行される(inAWhile関数)。

ホストプロセスは、発生したすべてのイベントを照合して、ハンドラーが登録されているかどうかを確認します。justNowが待機しているイベントが発生したことが判明したため、コードの実行を開始しました。justNow関数が終了すると、イベントループがもう一度チェックされ、イベントのハンドラーが検索されます。1秒が経過したとすると、inAWhile関数などが実行されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.