ノードには完全に異なるパラダイムがあり、それが正しくキャプチャされると、問題を解決するこの異なる方法を簡単に確認できます。同じことをする別の方法があるので、Node application(1)で複数のスレッドを必要とすることはありません。複数のプロセスを作成します。ただし、たとえば、Apache Web ServerのPrefork mpmが行う方法とは非常に異なります。
とりあえず、CPUコアは1つだけで、いくつかの作業を行うアプリケーションを(Nodeの方法で)開発するとします。私たちの仕事は、コンテンツをバイト単位で実行する大きなファイルを処理することです。私たちのソフトウェアの最良の方法は、ファイルの先頭から作業を開始し、バイト単位で最後まで作業を進めることです。
-ヘイ、ハサン、あなたは私の祖父の時代からの初心者か非常に古い学校のどちらかだと思います!!! いくつかのスレッドを作成して、それをはるかに高速にしてみませんか?
-ああ、CPUコアは1つしかありません。
- だから何?いくつかのスレッドの男を作成し、それをより速くします!
-そのようには機能しません。スレッドを作成すると、速度が遅くなります。スレッド間の切り替えのためにシステムに多くのオーバーヘッドを追加し、それらにわずかな時間を与えようとし、プロセス内でこれらのスレッド間の通信を試みます。これらすべての事実に加えて、並行して実行できる1つのジョブを複数の部分にどのように分割するかについても考えなければなりません。
-わかった、わかった、あなたは貧しい。私のコンピューターを使用してみましょう。32コアです!
-うわー、あなたは私の親愛なる友人、すごいです、ありがとうございました。それは有り難いです!
その後、仕事に戻ります。豊富な友人のおかげで、今では32個のCPUコアがあります。私たちが守らなければならないルールが変わりました。今、私たちは与えられたこのすべての富を利用したいと思います。
複数のコアを使用するには、並行して処理できる部分に作業を分割する方法を見つける必要があります。ノードでない場合は、これにスレッドを使用します。32スレッド、各CPUコアに1つ。ただし、Nodeがあるので、32のNodeプロセスを作成します。
スレッドは、Nodeプロセスの優れた代替手段になる可能性があり、おそらくより良い方法です。ただし、作業がすでに定義されており、その処理方法を完全に制御できる特定の種類のジョブでのみです。これ以外に、私たちが制御できない方法でジョブが外部から発生し、できるだけ迅速に応答したいという他のすべての種類の問題については、ノードの方法は間違いなく優れています。
-ヘイ、ハサン、まだシングルスレッドで作業していますか?どうしたの?私はあなたが望むものをあなたに提供したところです。言い訳はもうありません。スレッドを作成し、より高速に実行します。
-作業を細かく分割しましたが、すべてのプロセスがこれらの部分のいずれかで並行して動作します。
-なぜスレッドを作成しないのですか?
-申し訳ありませんが、使えないと思います。あなたが望むならあなたはあなたのコンピュータを取ることができますか?
-いいえ、大丈夫です。私はクールですが、なぜスレッドを使用しないのか理解できません。
-コンピューターありがとうございます。:)私はすでに作品を断片に分割し、これらの断片を並行して処理するプロセスを作成しています。すべてのCPUコアが完全に利用されます。プロセスの代わりにスレッドでこれを行うことができます。しかし、Nodeにはこの方法があり、上司のParth ThakkarがNodeを使用することを望んでいます。
-承知しました。別のコンピュータが必要かどうかをお知らせください。:p
32の代わりに33のプロセスを作成すると、オペレーティングシステムのスケジューラはスレッドを一時停止し、他のスレッドを開始し、いくつかのサイクルの後で一時停止し、他のスレッドを再起動します... いりません。実際には、32コアを搭載したシステムで、私も31をすることができ、正確に32のプロセスを作成したいとは思わないでしょう立派。このシステムで動作するのは私のアプリケーションだけではないからです。特に32の部屋がある場合は、他のことのために少し部屋を残すことは良いことです。
CPUを集中的に使用するタスクにプロセッサを完全に利用することについては、同じページにいると思います。
-うーん、ハサン、あなたを少しからかって申し訳ありません。私はあなたを今よりよく理解していると思います。しかし、まだ説明が必要なことがあります。何百ものスレッドを実行することについての話題は何ですか?私は、スレッドがforkプロセスよりもはるかに高速に作成および処理できないことをどこでも読んでいますか?スレッドの代わりにプロセスをフォークし、それがNodeで得られる最高のものだと思っています。では、Nodeはこの種の作業には適切ではないのでしょうか。
-心配いりません、私もかっこいいです。誰もがそういうことを言うので、聞き慣れていると思います。
- そう?ノードはこれに適していませんか?
-ノードはこれに完全に適していますが、スレッドも優れている場合があります。スレッド/プロセス作成のオーバーヘッドについては; あなたがたくさん繰り返すことについては、ミリ秒ごとに数えます。ただし、作成するプロセスは32のみであり、少し時間がかかります。それは一度だけ起こります。違いはありません。
-では、何千ものスレッドをいつ作成したいですか?
-何千ものスレッドを作成したくない。ただし、HTTPリクエストを処理するWebサーバーなど、外部からの作業を実行しているシステムでは、リクエストごとにスレッドを使用している場合は、多数のスレッドが作成されます。
-ノードは違いますか?正しい?
- はい、正確に。これがNodeが本当に輝く場所です。スレッドはプロセスよりもはるかに軽量であるように、関数呼び出しはスレッドよりもはるかに軽量です。ノードはスレッドを作成する代わりに関数を呼び出します。Webサーバーの例では、すべての着信要求が関数呼び出しを引き起こします。
-うーん、面白いです。ただし、複数のスレッドを使用していない場合は、同時に1つの関数しか実行できません。大量のリクエストが同時にWebサーバーに到着した場合、これはどのように機能しますか?
-関数の実行方法については、一度に1つずつ、2つを並行して実行することはできません。つまり、単一のプロセスでは、一度に実行されるコードのスコープは1つだけです。OSスケジューラは、プロセスを一時停止して別のプロセスに時間を与えるのではなく、この関数を一時停止して別の関数に切り替えません。プロセス内の別のスレッドではありません。(2)
-では、プロセスは一度に2つのリクエストをどのように処理できますか?
-システムに十分なリソース(RAM、ネットワークなど)がある限り、プロセスは一度に数万のリクエストを処理できます。これらの関数の実行方法は、主な違いです。
-うーん、今興奮する必要がありますか?
-多分:)ノードはキューでループを実行します。このキューには私たちの仕事、つまり着信リクエストの処理を開始した呼び出しがあります。ここで最も重要な点は、実行する関数を設計する方法です。リクエストの処理を開始して、ジョブが完了するまで呼び出し側を待機させるのではなく、許容できる量の作業を行った後、関数をすばやく終了します。別のコンポーネントが処理を実行して値を返すのを待つ必要があるポイントに到達したら、それを待つのではなく、残りの作業をキューに追加する関数を終了するだけです。
-複雑に聞こえますか?
-いいえ、私は複雑に聞こえるかもしれません。しかし、システム自体は非常にシンプルで、完全に理にかなっています。
これら2つの開発者間の対話の引用をやめ、これらの関数がどのように機能するかについての最後の簡単な例の後で私の答えを終えたいと思います。
このようにして、OSスケジューラが通常行うことを実行しています。ある時点で作業を一時停止し、他の関数呼び出し(マルチスレッド環境の他のスレッドなど)を再び実行するまで実行させます。これは、システム上のすべてのスレッドにただ時間を与えようとするOSスケジューラに作業を任せるよりもはるかに優れています。私たちは、OSスケジューラよりも優れていることを理解しており、停止する必要があるときに停止することが期待されています。
以下は、ファイルを開いて読み取り、データを処理する簡単な例です。
同期方法:
Open File
Repeat This:
Read Some
Do the work
非同期の方法:
Open File and Do this when it is ready: // Our function returns
Repeat this:
Read Some and when it is ready: // Returns again
Do some work
ご覧のとおり、この関数はシステムにファイルを開くように要求し、ファイルが開かれるのを待ちません。ファイルの準備が整った後、次のステップを提供することによってそれ自体を終了します。戻ると、Nodeはキューで他の関数呼び出しを実行します。すべての関数を実行した後、イベントループは次のターンに移動します...
要約すると、Nodeはマルチスレッド開発とはまったく異なるパラダイムを持っています。しかし、これは物事が不足しているという意味ではありません。同期ジョブ(処理の順序と方法を決定できる場所)では、マルチスレッド並列処理と同様に機能します。サーバーへのリクエストのような外部からのジョブの場合、それは単に優れています。
(1)C / C ++のような他の言語でライブラリを構築する場合を除き、その場合でも、ジョブを分割するためのスレッドは作成しません。この種の作業には、2つのスレッドがあり、1つはノードとの通信を継続し、もう1つは実際の作業を行います。
(2)実際、最初の脚注で述べたのと同じ理由で、すべてのNodeプロセスには複数のスレッドがあります。しかし、これは1000スレッドが同様の作業を行うようなものではありません。これらの追加スレッドは、IOイベントを受け入れたり、プロセス間メッセージングを処理したりするためのものです。
更新(コメントで良い質問への返信として)
@マーク、建設的な批判をありがとう。Nodeのパラダイムでは、キュー内の他のすべての呼び出しが次々に実行されるように設計されていない限り、処理に時間がかかりすぎる関数を使用してはなりません。計算量の多いタスクの場合、全体像を見ると、「スレッドまたはプロセスを使用する必要があるか」という問題ではないことがわかります。しかし、「これらのタスクをバランスのとれた方法でサブタスクに分割して、システム上で複数のCPUコアを使用して並行して実行できるようにするにはどうすればよいか」という疑問があります。8コアのシステムで400ビデオファイルを処理するとします。一度に1つのファイルを処理する場合は、同じファイルの異なる部分を処理するシステムが必要です。その場合、マルチスレッドのシングルプロセスシステムの構築がより簡単になり、さらに効率的になります。複数のプロセスを実行し、状態の共有/通信が必要な場合にそれらの間でメッセージを渡すことにより、Nodeを引き続き使用できます。前に述べたように、Nodeを使用したマルチプロセスアプローチは同様にここでのタスクの種類でマルチスレッドアプローチ。それ以上ではありません。繰り返しますが、以前に言ったように、Nodeが優れているのは、複数のソースからのシステムへの入力としてこれらのタスクを受け取ったときです。Node内の多くの接続を同時に維持することは、接続ごとのスレッドや接続ごとのプロセスに比べてはるかに軽いためです。システム。
setTimeout(...,0)
通話に関しては; 時間がかかるタスクの実行中に休憩を取り、キュー内の呼び出しが処理を共有できるようにする必要がある場合があります。タスクをさまざまな方法で分割することで、これらを回避できます。ただし、これは実際にはハックではなく、イベントキューが機能する方法にすぎません。また、をprocess.nextTick
使用setTimeout
すると、経過時間の計算とチェックが必要になるため、この目的に使用する方がはるかに優れprocess.nextTick
ています。 」