JavaScript が単一のスレッドで実行されることはよく知られています。この概念は非常に不可欠であるため、私たちはそれを メイン スレッド という名前で呼ぶことがよくあります。ということは、JavaScript の実行時にはマルチコア CPU が役に立たないということでしょうか?
そうではありません。
JavaScript は少し生意気で、スレッドに関するさまざまなメッセージを送信することがあります。
ただし、Web Workers や WebAssembly などのより複雑な機能を詳しく調べなくても、基本的な JavaScript でマルチスレッド ワークフローを利用できます。
明確にするために、この記事は Web ブラウザーベースの JavaScript に焦点を当てています。 Node.js などの他の環境では、処理が異なる場合があります。
JavaScript でのマルチスレッドおよびマルチスレッドのような操作のオプションを検討していきます。実際には、基本的な純粋なバニラ JavaScript でマルチスレッド ワークフローを利用できますし、そうすべきです。
嬉しいです。
JavaScript はシングルスレッド言語ですが、Web ブラウザによって解釈されます。ブラウザはマルチスレッド ソフトウェアです。
マルチスレッドをシミュレートして利用する方法はいくつかあり、あなたも気づかずにそれらを使用しているかもしれません。
さらに、JavaScript は、実際にはマルチスレッドであるにもかかわらず、マルチスレッドのように動作することがよくあります。不正行為のように聞こえるかもしれませんが、マルチスレッドの動作から期待される利点を効果的に提供します。
JavaScript はイベントベースのシステムです。ブラウザは JavaScript ファイルを処理するときに、内部のすべてのコードを実行します。実行を停止しないコードを記述することは完全に可能ですが、ブラウザがクラッシュする可能性があるため、一般的には悪い考えです。
私たちが通常行うことは、イベント リスナーをセットアップして、何かが起こるのを待つことです。この時点で、JavaScript は完全にアイドル状態です。このアイドル待機は、メインスレッドから一部の作業をオフロードしない限り不可能です。
イベント自体はマルチスレッドではありませんが、イベントの待機と確認は JavaScript ではなくブラウザーによって処理されます。このプロセスはメインスレッドからオフロードされます。
setTimeout や setInterval などの関数は、長年にわたって使用されてきました。メインスレッドから待機時間をオフロードします。
これがどのように機能するかを単純化してみましょう。低レベル言語では、タイマーや待機は、「もう時間ですか?」を常にチェックすることによって実装されることがよくあります。経過時間をチェックし、適切な時間が来たら続行する while() ループを想像してください。最新のアプローチでは、CPU スレッドの詰まりを避けるために CPU 割り込みを使用する場合があります。
ただし、JavaScript で setTimeout または setInterval を使用すると、言語は待機中に完全にアイドル状態になります。これは、繰り返しますが、待機がメイン スレッドから何らかの方法で処理されることを意味します。
最近では、ブラウザーから非同期関数や API がますます増えています。フェッチ API はよく知られた例です。 Clipboard API などの新しい API も非同期です。
これは、ブラウザにアクションの実行を要求することを意味し、JavaScript のメイン スレッドが解放され (または、他の処理ができるようになります。詳細は後ほど)、それが完了すると (次のコードを処理することで) 通知されます。
非同期は、必ずしもマルチスレッドを意味するわけではありません。常に、直接というわけではありません。関数の前に async という単語を置くだけでは、何の役にも立ちません。
JavaScript が非同期動作を処理する方法には 2 つの重要なコンポーネントがあります。
コールバック キューは、実行を待機している一連の関数と考えてください。これらの関数はメインスレッドで 1 つずつ実行されます。非同期操作が完了すると (イベント、タイムアウト、フェッチ完了など)、そのコールバックがこのキューに配置されます。
イベント ループは、コール スタックが空のときにコールバックをキューからコール スタックに移動する役割を果たします。
Web ブラウザは特定の操作を制御し、その操作のために新しいスレッドを起動する場合があります。これには、fetch や setTimeout などのアクションが含まれます。 JavaScript はこれらのスレッドを管理する必要はありません。非同期操作が完了すると、ブラウザーは対応するコールバックをコールバック キューに配置し、そこから JavaScript が実行を継続します。
次のコードを考えてみましょう:
console.log('Start'); setTimeout(() => { console.log('This is asynchronous'); }); console.log('End');
出力:
Start End This is asynchronous
以下のことが起こります:
setTimeout にタイムアウト パラメーターが欠落していることに注意してください。これは、優先度の低いコードの実行を延期する一般的な手法です。最初に他のすべてを処理し、それが完了したら、「優先度の低い」処理を実行します。
これにより、setTimeout 内の関数がコールバック キューに即座に配置され、メイン スレッドがアイドル状態になったときに最初の機会に実行されます。
requestAnimationFrame は、ビュー (ビデオ ゲームにおける 1 秒あたりのフレーム数と考えてください) を計算して更新する直前に、ブラウザにコードの実行を指示するブラウザ API です。
何らかの理由で、Web 開発者は再描画や FPS について考えませんが、それが仕組みです。
本質的に非同期です (ただしマルチスレッドではありません)。
時間を指定せずに setTimeout を使用することは、requestAnimationFrame が導入される前は同様の目的でよく使用されていましたが、それほど便利とは言えませんでした (何もしないよりは良いだけです)。
この関数は、コードを特別なスタックにキューに入れます。新しいフレームをレンダリングする (再描画) 直前に、ブラウザーはキューに入れられたこのコードを実行します。これは、DOM、HTML、または CSS に変更を加えるのに最適です (ただし、これらのみで計算を行うことは禁止します!)。
この記事はそれらに関するものではありませんが、Web Workers と WebAssembly を利用することで真のマルチスレッド操作を実現できることは言及する価値があります。これらにより、バックグラウンド スレッドでスクリプトを実行できるようになります。 DOM を直接操作することはできませんが、重いタスク (行列計算など) を処理するのに非常に役立ちます。このアプローチは、三目並べだけでなく、より複雑な HTML5 ベースのゲームでよく使用されます。
JavaScript は、分離されてもシングルスレッドのままです。しかし、現実の世界では、これは Web ブラウザのマルチスレッド環境内で実行されるインタプリタ型言語です。通訳者があなたに助けの手を差し伸べてくれたら、それを受け入れて使ってください。
この記事では、基本的な知識、低レベルの説明など、多くの内容を取り上げます。しかし、開発は多くの場合そのように行われ、すべてが相互に関連しています。だからこそ、私はより広い視野で見ることを好むのです。場合によっては、詳細に焦点を当てても問題の解決策にならないことがあります。
非同期がデバッグの悪夢を引き起こしたことがありますか?
私も確かにそう思っています。数年前には、エラーのあるスタックを取得することは大したことではありませんでした。
以上がJavascript でマルチスレッドを利用する - WebWorkers や WebAssembly についてではないの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。