14日目の記事となります。Threadsに関してまとめます。おける内容をまとめています。worker_threadはexperimentalな機能なので、今後仕様が変わりうるので注意が必要です。10.5.0より、Node.jsでのスレッドプログラミングを可能にするworker_threadsモジュールが追加されました。worker_threadsモジュールを利用可能です。contributorによるFAQを読んでみると、このモジュールが取り入れられた背景を知ることができます。I/Oバウンドな処理でなく、CPUバウンドな処理に用いると効率的になります。processやclusterモジュールと違って、ArrayBufferインスタンスの転送や、SharedArrayBufferインスタンスの共有によって、メモリ空間を効率的に共有できます。ドキュメントに記載されているサンプルコードを抜粋すると以下となります。isMainThreadがtrueかどうかで判定して分岐させています。Workerインスタンスを生成する際の引数で別のファイルを指定することで、mainスレッド、Workerスレッドの処理を別ファイルで分けてかけます。parentPort.postMessageによってmainスレッドにメッセージを送信しています。MessagePortクラスについて説明します。worker_threadを使う際の各機能の解説をします。詳細を知りたい方は公式ドキュメントを参照ください。workerスレッド内で実行されている場合はfalseとなります。workerで処理を分けたい場合はこれで判定します。worker.parentPortparentPortはMessagePortクラスのインスタンスで、mainスレッドとコミュニケーションを可能にします。mainスレッド環境でworker.on('message')イベントのハンドラ内で使うことができます。MessagePortクラスについては後ほど説明します。worker.threadId現在のスレッドを識別するための整数idです。workerスレッドでは生成した順に1から増えていきます。このthreadIdが0かどうかで判定しています。0;worker.workerDataWorkerインスタンスの生成時にコンストラクタに渡されたデータを、workerスレッドでの実行時に使うことができます。workerDataとして使える様になっています。GitHubここで、上記のプロパティをつかって簡単なプログラムを書いてみます。${threadId}`)}実行結果は以下のとおりです。独立したJavascript実行スレッドを表現するものです。worker_threadモジュールにおいておそらく一番重要なので、詳しくまとめます。環境内での注目すべき違いは以下のとおりです。下記の項目関しては対応待ちとなっているようです。workerインスタンスを作成することは可能です。Workerクラスの内部実装WorkerクラスについてのNode.jsの実装を見ていきます。Workerクラスは、EventEmitterを継承しています。https://github.com/nodejs/node/blob/v10.14.1/lib/internal/worker.js#L252スレッド間でのメッセージ受信や、スレッド終了のタイミングでイベントを発火します。Workerクラスのコンストラクタでインスタンス生成処理の最後でスレッドを開始します。Workerによってインスタンスが生成されるタイミングで、Workerスレッドが始動します。node/src/node_worker.ccの方で、livuvのuv_thread_createをつかってスレッド開始しているのがわかります。下記の場所でWorkerスレッドに関するセットアップが行われます。このlivuvのuv_thread_createについて調べる必要がありますが、今回は説明しません。非同期の2-wayコミュニケーションチャネルを提供します。javascriptのMessageChannelクラスを踏襲しているようです。port2プロパティを持っています。});MessagePortクラスMessagePortクラスのインスタンスは非同期の2wayコミュニケーションチャンネルの片方のチャンネルを表現するものとなります。Workerクラスと同様にEventEmitterを継承しています。EventEmitter.prototype);前述したコードでも書いているように、MessagePort#postMessage()によって、スレッド間でデータをやり取りできます。worker間でcloneせずにメモリを共有してやり取りできます。worker_threadで大事なものに関しては以上のとおりです。実際にプログラムを書きつつ調べると理解が深まるかと思います。Workerスレッドでcpuバウンドな処理をさせてみる。一通り説明できましたので、ここでmainスレッドと\workerスレッドでプログラムを分けた上で、5つのWorkerスレッドで重いループ処理を行うプログラムを書きます。workerで行う処理をざっくり説明すると以下のとおりです。main_thread.jsに記述します。worker_threadsモジュールをrequireしてisMainThreadとWorkerを読み込んでます。Workerしてインスタンスを生成します。Workerの第1引数にパスを指定します。heavy_thread.jsの実装は下記のとおりです。4これでmain・workerスレッド間でメッセージをやりとりできました。速度について調べます。厳密に同じ処理ではないので正しく計測はできていないですが。シングルスレッドでの実行プログラムは以下のように書きました。10000のループ処理を5回行うプログラムです。--experimental-workerフラグを付けて実行したmain_thread.jsの実行時間を比較します。実行時にtimeコマンドを使って算出したものです。約1/4となり、かなり実行時間を短縮できたことがわかりました。この場合、マルチコア・マルチスレッドでの並列実行の恩恵をうまく受けていること示唆する結果とのことでした。advantage.さいごにworker_threadモジュールによって、Node.jsでのマルチスレッドプログラミングが可能になり、cpuバウンドな処理をさせたいときには活用したいと思いました。多少仕組みを学ぶのに労力がかかったのですが、worker_threadのラッパーであるmicrojobというモジュールも人気なので、こちらを使うと楽に書けるのではと思います。http/2の実装がマージされました。優れた技術専門職になるためのガイド」の内容レビューに関わらせていただきました。4はてなブログをはじめよう!kaktsさんは、はてなブログを使っています。ブログを報告する引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。