Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8691

javascriptができるのは非同期処理であって並列処理ではない

$
0
0

はじめに

初投稿です
非同期処理と並列処理の違いをやっと理解できたのでそのことについて書きます。

並列処理

まず並列処理は複数スレッドを同時に立ち上げて処理を行う方式のことを言います。(マルチスレッド)

同期処理

同期処理とは通常の実行順番通りにプログラムが実行され実行が終わるまで次の処理に移らない、というような処理方式です。
javascriptは同期処理で処理が行われます。

以下のコードを実行すると、

sample1.js
functionsleep(n,name){n=n*1000letstart=Date.now();while(Date.now()-start<n){}console.log(name)}functionA(){// 重たい処理Asleep(1,"A");}functionB(){// 重たい処理Bsleep(2,"B");}functionC(){// 重たい処理Csleep(3,"C");}functionD(){A();B();C();}console.log("start");D();console.log("end");
start
// 1秒
A 
// 2秒
B 
// 3秒
C
end

となるはずです。

しかしこの方式では重たい処理があった場合にその処理が終わるまで次の処理に移ることができないというデメリットがあります。

非同期処理

同期処理のデメリットを解消することができるのが非同期処理です。
非同期処理に書き換えたコードが以下のコードです。

これを実行すると、

sample2.js
functionA(){// 重たい処理AreturnnewPromise(resolve=>{setTimeout(()=>{console.log('A');},1000);});}functionB(){// 重たい処理BreturnnewPromise(resolve=>{setTimeout(()=>{console.log('B');},2000);});}functionC(){// 重たい処理CreturnnewPromise(resolve=>{setTimeout(()=>{console.log("C")},3000);});}asyncfunctionD(){awaitPromise.all([A(),B(),C()]);}console.log("start");D()console.log("end");
start
end
// 1秒
A
// 1秒
B
// 1秒
C

となります。

function D()の中の処理が非同期で処理されるため、functionA、B、Cの実行が終わる前にendが先に出力されました。
また、function A、B、Cが同時に実行されているように見えます。
これが非同期処理です。

結局何が違うのか

ここまでの説明だけでは、

非同期処理 = 並列処理

のように見えます。自分も少し前まではそう思ってましたが、実際には違います。

以下のコードを実行してみてください。

sample3.js
functionsleep(n,name){n=n*1000letstart=Date.now();while(Date.now()-start<n){}console.log(name);}functionA(){// 重たい処理Asleep(1,"A");}functionB(){// 重たい処理Bsleep(2,"B");}functionC(){// 重たい処理Csleep(3,"C");}asyncfunctionD(){awaitPromise.all([A(),B(),C()]);}console.log("start");D();console.log("end");

javascriptの非同期処理が並列処理だとしたら、このコードは一つ上のコードと同じ結果になるはずです。

しかし実際には、

start
// 1秒
A
// 2秒
B
// 3秒
C
end

となります。
なぜこうなるのかと言うと、javascriptは基本的にシングルスレッドで実行されているからです。
このsleep()という関数はwhileループを使い時間を待っています。
つまり、sleep中はずっとwhileループが回ってます。
そのためpromise.all()しても同期処理と同じ結果になってしまいました。

それに対してsettimeout()という関数はNode core APIのTimerが実行されるためjavascript自体が回っているわけではなく処理を手放し、レスポンスを待っている状態です。
このレスポンス待ち状態に別のタスクを進める、というのがjavascriptにおける非同期処理です。
なので非同期処理は並列処理ではありません。
並列処理っぽく見えるだけです。

まとめ

  • javascriptはシングルスレッドで実行される
  • 非同期処理と並列処理は似ているが別物

非同期処理を理解するのはけっこう難しいですが、これを押さえておくだけでだいぶ理解しやすくなるんじゃないでしょうか?

参考文献

JavaScriptの非同期処理を並列処理と勘違いしていませんか?
同期処理、非同期処理、並列処理のざっくりとした違い
非同期処理ってどういうこと?JavaScriptで一から学ぶ
JavaScriptはシングルスレッドで実行される
内部実装から読み解くNode.js(v11.0.0) Eventloop
async function - MDN web docs


Viewing all articles
Browse latest Browse all 8691

Trending Articles