👌

Web Workerでマルチスレッド(JSのみ): Rustが征く(9)

2021/11/24に公開

web worker思ったよりやるじゃん

関連記事:

Rustが征くシリーズ過去記事

前回の記事で、
WebAssemblyのマルチスレッドはやや微妙な感じだとお話しした。
ただ、計測してみなきゃわからないので、
その実力を測る上で、
まずJavaScriptのマルチスレッド実装であるWeb WorkderAPIを試す。

JSの非同期処理で並列実行は可能だが、
それと同等の性能であれば、
十分実用的だといえる。

ソースコード全体は最後に載せるとして、
ここでは要点の説明にとどめる。

結論から言うと、
マルチスレッドの方が2倍速い
結果となった。

ヾ(・ω<)ノ" 三三三● ⅱⅲ コロコロ♪

------------------- ↓ 本題はここから ↓-------------------

メインスレッドの実装

メインスレッドから画像もなしにスレ立てをして、
実行プログラムをロードする。
navigator.hardwareConcurrency には自身のPCの最大処理数(コア数)が格納されている。
その回数分スレッドを立てる

./main.mjs
const maxWorkers = navigator.hardwareConcurrency || 4;
const workers = []

for (let i = 0; i < maxWorkers; i++) {
  workers[i] = new Worker(new URL('./worker.mjs', import.meta.url), {
    type: "module"
  });
  workers[i].addEventListener('message', (event) => {
    console.log("Data from worker"+i+" received: ", event.data);
  }, false);
}

for (let i = 0; i < 4; i++) {
  workers[i].postMessage("Hello from the main thread!");
}

Workerの実装

メインスレッドから間接的に呼ばれる実行プログラム。
単純に40億回のループ速度を測っている

./worker.mjs
const loop = () => {
    console.time("sleep")
    const billions = 4000000000
    for (let i = 0; i < billions; i++) {}
    console.timeEnd("sleep")
}

self.addEventListener('message', loop);

実行

同時処理数 平均(ms)
1 3395
2 3731
4 5024
8 6928

ソースはこちらに置いておく

マルチスレッドのソースコード

筆者のPCは
AMD Ryzen 5 3500U with Radeon Vega Mobile Gfx、2100 Mhz
8プロセッサまでいけるので同時に8まで実行させた。
(CPUによって変わるかもしれないが。)

ちなみに非同期(async)で擬似的に並列処理もできるがその結果は
こちら

同時処理数 平均(ms)
1 3825
2 4551
4 2620
8 1853

(?_?) こっちの方が速いやん

だがちょっと待って欲しい。

非同期ではあるが同時処理はされていないので、
かかった時間は8*1853=14,824ms。
マルチスレッドは同時処理しているので平均の6928msで全部完了。
マルチスレッドの方が倍の速度がでてることになる。

------------------- ↓ 後書はここから ↓-------------------

この記事読み返してみたら、全然意味わからんな。
まぁ、いいか。

Discussion