同じファイルの取得と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ループreadFileSync7.4100%
B約束チェーンreadFileSync4.4760%
C約束チェーンreadFile1.0915%
DPromise.all readFileSync4.5862%
EPromise.all readFile1.6923%
FマルチスレッドループreadFileSync20.05271%
Gマルチスレッドpromise.all readFile4.9867%

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


記号お名前ops /秒パーセント
AループreadFileSync747100%
B約束チェーンreadFileSync64186%
C約束チェーンreadFile12016%
DPromise.all readFileSync66489%
EPromise.all readFile23832%
FマルチスレッドループreadFileSync1050140%
Gマルチスレッドpromise.all readFile37250%

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


記号お名前ops /秒パーセント
AループreadFileSync0.6383%
B約束チェーンreadFileSync0.6687%
C約束チェーンreadFile0.6180%
DPromise.all readFileSync0.6687%
EPromise.all readFile0.76100%
FマルチスレッドループreadFileSync0.83109%
Gマルチスレッドpromise.all readFile0.81107%

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ループreadFileSync8.4774%
B約束チェーンreadFileSync6.2855%
C約束チェーンreadFile5.4948%
DPromise.all readFileSync8.0670%
EPromise.all readFile11.05100%
FマルチスレッドループreadFileSync3.7132%
Gマルチスレッドpromise.all readFile5.1144%

100ファイルを読むとき


記号お名前ops /秒パーセント
AループreadFileSync79.1985%
B約束チェーンreadFileSync50.1754%
C約束チェーンreadFile48.4652%
DPromise.all readFileSync54.758%
EPromise.all readFile92.87100%
FマルチスレッドループreadFileSync80.4686%
Gマルチスレッドpromise.all readFile92.1999%

キャッシュされていないファイルを読み取るときのプロセッサの負荷は小さく、約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-読み取り結果を受け取り、データを処理します。



Source: https://habr.com/ru/post/J337746/


All Articles