データを抽出してみよう(kinenote編その3)
ブロトピ:今日のブログ更新
ブロトピ:ブログ更新通知をどうぞ!
ブロトピ:ブログ更新通知
ブロトピ:ブログ更新しました!
前回までの話
前回のテスト実行で直列実行するよりPromise#all()を使用した並行実行処理の方が処理も早く、サーバにも負荷を掛けずに実行できるので並行実行処理が適切だと分かりました。
しかし、並行実行が早くても1000件実行するのに30分程かかり、もう少し時間短縮出来ればと思い調査していました。
単純に並行実行する数を増やしてもNode.jsの並行実行はシングルスレッドのため、速度アップは無理でした。
後は現状のロジックで何か速度アップが望める所はないか確認して、マインパワーを上げてテストしてみようかという所です。
という事で改めてロジックを見直してみましたが、現状のスクレイピングツールのロジックは、内部的にはHTTP GETして、HTMLスクレイピングして、結果を保存する。というシンプルな流れでPromise形式の直列処理してるだけなので、余計な処理があるわけではないので、とりあえずマシンパワーに頼ってみようと思います。
Azure の仮想マシンで実行(Ubuntu)
AzureポータルでUbuntu18の仮想マシンを作りました。
マシンサイズは「Standard D2s v3 (2 vcpu 数、8 GB メモリ)」でとりあえず作成。
/proc/cpuinfoによると2.4GHのCPUらしい。
当方のクライアントPC (Intel 3.3GH Core 2) と比べると若干クロック値が低い気もしますが、そんなに大差は無いですね。
Node.jsの実行環境構築は以下を参考にしました。
ソースをデプロイ後、以下の2パターンでテストしました。
- Standard D2s v3 (2 vcpu 数、8 GB メモリ)(CPU2.4GH)
- Standard D4s v3 (4 vcpu 数、16 GB メモリ)(CPU2.4GH)
結果、マシンパワー上げても無意味な事が分かりました。がっかり。。。
時間掛かってるのは保存処理じゃなくて、HTTPリクエスト、スクレイピング周りなので、HTTPリクエストの応答待ち時間が大半なんだろうか。。。
結局の所、シングルスレッドの並行実行では、ある処理が重ければ、後続の処理がそのまま待ち時間になってしまうのでスピードアップは望めないようです。
やはりスピードアップするならマルチスレッド化が必須なようで。
マルチスレッドプログラミング
Node.jsでマルチスレッドを実現するためには「Worker Threads」というモジュールを使う必要があります。
しかし、Stable版の10.15では「Experimental」となっており、テスト実装中らしいので今後変更される可能性があるようです。
そして、忘れてはいけないのがnode.js実行時のオプションで「–experimental-worker」を指定する必要があります。これを忘れて「Worker Threads」を使用したnode.jsをいつものように起動(node .\hoge.js)すると「そんなモジュール無いよ」って言われます。
必ず「node –experimental-worker .\hoge.js」の形式で起動してください。
ちゃんとドキュメント見れば書いてありますから。ええ。私は見落としててバージョンアップしないとダメなのかな?とか思ってしまいましたが。。。
サンプルは以下が参考になります。
なお、もともとNode.jsは必要に応じて裏でマルチスレッド処理してる事もあるようです。
以下のページが面白かったです。
マルチプロセスプログラミング
マルチスレッドは1つのプロセスを複数のスレッドという小さな単位で分割してそれらを並列処理するもの。マルチプロセスはプロセスが複数あって、それらを並列処理するもの。
やり方は2通りで「Child Process」か「Cluster」というモジュールを使う方法。
参考リンクは以下より。
ただいま勉強中
マルチプロセスかマルチスレッドかという選択問題もありますが、色々時間掛けてじっくりやろうかと思います。