再びインターネット上で誰かが間違っています-昨日Node Weeklyで、著者がNode.jsでStream APIのパフォーマンスを測定および比較しようとしている投稿へのリンクがありました。 悲しみは、著者がストリームをどのように扱うか、そしてこれに基づいて彼がどのような結論を下そうとしているのかを引き起こします:
...これは小さなファイルでもかなりうまくいきましたが、最大のファイルに到達すると同じエラーが発生しました。 Node.jsは入力と出力をストリーミングしていましたが、操作の実行中にファイル全体をメモリに保持しようとしました
著者の結論とコードの何が悪いのかを考えてみましょう。
私の観点から見ると、問題は記事の著者がStream'amiの使い方を知らないことであり、これは非常に頻繁に対処しなければならない問題です。 私の意見では、この現象には3つの理由があります。
- Node.jsストリームAPIの複雑なストーリー- ここで説明する痛みと苦しみ
- ラッパーなしで使用しようとすると、最も直感的なAPIではありません
- ストリームを非常に複雑で低レベルなものとして提示するかなり奇妙なドキュメント
まとめると、これは開発者がStream APIを使用する方法を知らず、使用したくないという事実につながります。
著者コードの何が問題になっていますか?
まず、ここでタスクを繰り返しましょう(英語のオリジナルとファイルへのリンクは投稿にあります):
次の形式の行を持つ特定の2.5 GBファイルがあります。
C00084871|N|M3|P|201703099050762757|15|IND|COLLINS, DARREN ROBERT|SOUTHLAKE|TX|760928782|CELANESE|VPCHOP&TECH|02282017|153||PR2552193345215|1151824||P/R DEDUCTION ($76.92 BI-WEEKLY)|4030920171380058715
それを解析して、次の情報を見つける必要があります。
- ファイルの行数
- 432行目と43243行目の名前(ここで、0または1から数える方法の問題は真実ですか?)
- 最も一般的な名前とその発生回数
- 各月の分割払いの数
問題は何ですか? -作成者は、ファイル全体をメモリにロードすると正直に言います。そのため、ノードは「ハング」し、興味深い事実を示してくれます。
楽しい事実:Node.jsは、一度に最大1.67GBのメモリしか保持できません
著者は、この事実から奇妙な結論を下し、ファイル全体をメモリにロードするのはストリームであり、間違ったコードを書いていないということです。
論文を反証しましょう:「 Node.jsは入力と出力をストリーミングしていましたが、ファイルの行数を数える小さなプログラムを書くことで、 ファイル全体を保持しようとしています。 」
const { Writable } = require('stream') const fs = require('fs') const split = require('split') let counter = 0 const linecounter = new Writable({ write(chunk, encoding, callback) { counter = counter + 1 callback() }, writev(chunks, callback) { counter = counter + chunks.length callback() } }) fs.createReadStream('itcont.txt') .pipe(split()) .pipe(linecounter) linecounter.on('finish', function() { console.log(counter) })
NB :コードは意図的に可能な限り単純に書かれています。 グローバル変数は悪いです!
次のことに注意してください。
- split-文字列のストリームを「入力」として受け取るパケットnpm-文字列のストリームを改行で区切られた「個別の」出力として返します。 ほとんどの場合、変換ストリームの実装として作成されます。 ReadStreamをファイルでパイプ処理し、それ自体をパイプ処理して...
- linecounter-WritableStreamの実装。 その中で、2つのメソッドを実装します。1つのピース(チャンク)と複数のピースを処理します。 この状況での「行」はコードの行です。 リバース-カウンターに目的の数を追加します。 この状況では、ファイル全体をメモリにロードせず、APIがすべてを処理に最も便利な「ピース」に分割することを理解することが重要です
- 「終了」-ReadableStreamに到着したデータが「終了」したときに「発生」するイベント。 これが発生すると、カウンターデータを誓約します
それでは、大きなファイルで作成をテストしてみましょう。
> node linecounter.js 13903993
あなたが見ることができるように-すべてが動作します。 このことから、Stream APIはあらゆるサイズのファイルで優れた仕事をしており、投稿の著者の声明は控えめに言っても真実ではないと結論付けることができます。 ほぼ同じ方法で、問題に必要な他の値を計算できます。
伝える:
- 問題を完全に解決する方法と、生成されたコードを保守に便利な形にする方法を読むことに興味がありますか?
- Stream APIを使用していますか?また、どのような困難に遭遇しましたか?