同じファイルの取得とfs.readFileSyncおよびfs.readFileの比較(および複数のファイルの読み取り)

記事「 エピソード8:Node.jsの作成者であるRyan Dahlのインタビューと 翻訳に関するコメント」を読んだ後、Node.jsのブロックおよびノンブロッキングファイル読み取り操作の有効性を、テーブルとグラフィック猫の下でテストすることにしました。







UPD:アンダーカットは誤ったベンチマークです。 コメントが正しく指摘したように、基本的にfs.readFileSyncとfs.readFileを使用して同じファイルのキャッシュを比較します。







UPD2:記事が編集され、ベンチマークが修正され、結果が追加されました。







ブロッキング操作(fs.readFileSyncはこれらの1つです)は、JSに直接関連する操作が完了するまで、アプリケーション全体の実行が中断されることを前提としています。







非ブロッキングオプションにより、非JS操作を並列スレッドで非同期に実行できます(例:fs.readFile)。







ブロックと非ブロックの詳細については、 こちらをご覧ください







Node.jsは、child_processまたはclusterを使用して単一のスレッドで実行されますが、コードの実行を複数のスレッドに分散できます。







テストは、キャッシュファイル(大規模および小規模)の並列および順次読み取り、および非キャッシュファイルの読み取りで実行されました。







すべてのテストは、1台のコンピューターと1台のHDD、およびimmenoで行われました。







OS:Ubuntu 16.04

Node.jsバージョン:8.4.0

プロセッサー:AMD Phenom(tm)9750 Quad-Core Processor

物理コア:4

HDD:2TB 7200rpm 64MB

ファイルシステムタイプ:ext4

file.txtサイズ:3.3 kB

bigFile.txtサイズ:6.5 MB

キャッシュファイルの結果。







3.3 kBファイルを10,000回読み取る場合







記号 お名前 ops /秒 パーセント
A ループreadFileSync 7.4 100%
B 約束チェーンreadFileSync 4.47 60%
C 約束チェーンreadFile 1.09 15%
D Promise.all readFileSync 4.58 62%
E Promise.all readFile 1.69 23%
F マルチスレッドループreadFileSync 20.05 271%
G マルチスレッドpromise.all readFile 4.98 67%


3.3 kBファイルを100回読み取る場合







記号 お名前 ops /秒 パーセント
A ループreadFileSync 747 100%
B 約束チェーンreadFileSync 641 86%
C 約束チェーンreadFile 120 16%
D Promise.all readFileSync 664 89%
E Promise.all readFile 238 32%
F マルチスレッドループreadFileSync 1050 140%
G マルチスレッドpromise.all readFile 372 50%


6.5 MBファイルを100回読み取る場合







記号 お名前 ops /秒 パーセント
A ループreadFileSync 0.63 83%
B 約束チェーンreadFileSync 0.66 87%
C 約束チェーンreadFile 0.61 80%
D Promise.all readFileSync 0.66 87%
E Promise.all readFile 0.76 100%
F マルチスレッドループreadFileSync 0.83 109%
G マルチスレッドpromise.all readFile 0.81 107%


3.3 kBファイルを10,000回読み取り中のCPU使用率

file.txt、読み取り10000回







6.5 MBファイルを100回読み取り中のCPU使用率

bigFile.txt、読み取り回数100回







ご覧のとおり、fs.readFileSyncは常に1つのコアの1つのスレッドで実行されます。 fs.readFileはその作業でいくつかのスレッドを使用しますが、カーネルは最大容量でロードされません。 小さなファイルの場合、fs.readFileSyncはfs.readFileよりも高速に実行され、同じスレッドで実行されているノードで大きなファイルを読み取る場合のみ、fs.readFileはfs.readFileSyncよりも高速に実行されます。







したがって、fs.readFileSyncを使用して小さなファイルを読み取り、fs.readFileを使用して大きなファイルを読み取ることをお勧めします(ファイルの大きさはコンピューターとソフトウェアによって異なります)。







一部のタスクでは、fs.readFileSyncは大きなファイルの読み取りにも適している場合があります。 たとえば、多くのファイルを長時間読み取って処理する場合。 この場合、カーネル間の負荷はchild_processを使用して分散する必要があります。 大まかに言って、複数のスレッドでの操作ではなく、ノード自体を実行します。







UPD2

以下は、同じサイズ(3.3kB)の多くのキャッシュされていないファイルを読み取るために取得されたデータです。







1000ファイルを読むとき







記号 お名前 ops /秒 パーセント
A ループreadFileSync 8.47 74%
B 約束チェーンreadFileSync 6.28 55%
C 約束チェーンreadFile 5.49 48%
D Promise.all readFileSync 8.06 70%
E Promise.all readFile 11.05 100%
F マルチスレッドループreadFileSync 3.71 32%
G マルチスレッドpromise.all readFile 5.11 44%


100ファイルを読むとき







記号 お名前 ops /秒 パーセント
A ループreadFileSync 79.19 85%
B 約束チェーンreadFileSync 50.17 54%
C 約束チェーンreadFile 48.46 52%
D Promise.all readFileSync 54.7 58%
E Promise.all readFile 92.87 100%
F マルチスレッドループreadFileSync 80.46 86%
G マルチスレッドpromise.all readFile 92.19 99%


キャッシュされていないファイルを読み取るときのプロセッサの負荷は小さく、約20%です。 結果は±30%異なります。

結果は、非ブロッキングfs.readFileを使用する方がより有益であることを示しています。







ファイル読み取り状況の例。







1つのスレッドT1のノードでWebサーバーが回転しているとします。 2つの要求(P1およびP2)が同時に小さなファイル(要求ごとに1つ)を読み取り、処理します。 fs.readFileSyncを使用する場合、T1ストリームでのコード実行のシーケンスは次のようになります。







P1-> P2







fs.readFileを使用する場合、T1ストリームでのコード実行のシーケンスは次のようになります。







P1-1-> P2-1-> P1-2-> P2-2







P1-1、P2-1-別のストリームに読み取りを委任する場合、P1-2、P2-2-読み取り結果を受け取り、データを処理します。








All Articles