node.js に固有のシングルスレッド プログラミングとコールバック関数の非同期スタイルは、私たちを時には幸せにし、時には不安にさせます。まずシングルスレッドについて話しましょう。node.js のシングルスレッドがどのようにして高い同時実行性を実現できるのか疑問に思う人は多いのではないでしょうか。この問題はこの記事の焦点ではないので、ここでやめましょう。明確にするために、node.js のシングル スレッドはシングル スレッドの JavaScript エンジンのみを指します。いずれにしても、JavaScript でマルチスレッドとブロックを実装する方法はありません (この記事で使用されているメソッドも、 V8 エンジン); ただし、ノード用 .js の他の側面は、IO など、マルチスレッドに対応できないことを意味するものではありません。現在、node.js が多数のリクエストを受けており、これらのリクエストが IO 集中型である場合、ノードがリクエストを受け入れるたびに、長い IO 操作が発生したときに JavaScript スレッドが常にここで待機するわけではなく、代わりに制御を引き渡します。 IO 操作の完了後に実行される操作をコールバック スタックに追加します (コールバック レベルが多すぎてアクセス数が多すぎる場合、多数のコールバック チェーンがスタックをバーストする可能性があります)。この間、node.js は他のリクエストを処理できます。したがって、node.js の場合、JavaScript はシングルスレッドであり、一度に 1 つのリクエストしか処理できませんが、JavaScript がリクエストを処理できる限り、リクエストの処理にかかる時間は短縮されることがよくあります。非同期的に、その後、処理中に、このリクエストは制御を解放し、node.js が他のリクエストを処理できるようにします。この同時リクエスト中、実際には IO は常に同時状態にあり、リクエストを処理するスレッドの数が減り、通常は長時間かかる IO 集中型リクエストの場合はリソースが節約され、パフォーマンスが向上することは間違いありません。 。 推進する。
私はこれまでIO集中性を強調してきましたが、実際にはnode.jsの長所を強調しています。それに応じて、CPU に負荷がかかるリクエストが欠点になります。理由は非常に単純で、JavaScript は同時実行されず、他のリクエストは 1 つのリクエストが完了した後でしか処理できないためです。 1 つのリクエストの処理に時間がかかるほど、他のリクエストの待機時間も長くなります。同時に処理されるリクエストは 1 つだけであり、同時実行パフォーマンスは非常に低くなります。
そうは言っても、明確にしておきたいのは、node.js はブロックされるべきではないということです。非同期で処理できるメソッドは非同期で処理されます (fs.syncReadFile() の代わりに fs.readFile() を使用するなど)。 () 方法) 。
ノード内でブロックできませんが、ノード外でブロックできないわけではありません。先ほど ファイバー について説明しました。次に、ファイバーにブロッキングを実装してみましょう。例として http リクエストを処理してみましょう:
yield() メソッドと run() メソッドに慣れていない学生は、「ノード内のファイバー」を自分で確認してください。
ファイバーはノード プロセス内で実行されないため、ファイバー内のブロックはノードの全体的なパフォーマンスに影響を与えません。実装は非常に簡単です。ブロックしたいときにファイバーを渡すだけです。実行を継続する必要がある場合は、run() を実行してファイバーを復元します。上の例では、http.get リクエストが開始されたときに現在のプログラムをブロックし、すべてのデータの受信が完了したときにプログラムを再開したいと考えています。そこで、http.get を呼び出した後、Fiber.yield() を使用してこのファイバーを中断します。応答を監視する際、終了イベントがトリガーされると、データ送信が完了したことを示すため、終了コールバック関数で Fiber.current.run() を呼び出してファイバーを復元します。このようにして、後続のコードが取得されます。 http.get を同期的に取得します。
上記の例は、アイデアを提供するためのものです。たとえば、このアイデアを抽象的にカプセル化した場合、コールバック関数をパラメータとして受け入れる非同期メソッドでワンステップ カリー化を実行し、呼び出し後に中断し、コールバック関数をハイジャックしてプログラムのコードをコールバックとして復元します。関数。非同期データを取得した後、プログラムは所定のコールバック関数をトリガーします。これにより、基本的に非同期メソッドの同期を実現できます。この段落は非常にわかりにくいですが、基本的には fibers/future の実装アイデアです。興味がある場合は、ソース コードを参照してください。