これは私が掘り下げた個人的なプロジェクトです。基本的には、私はStreamReaderを使ってテキストファイル(20MBから約1GBまで)を解析します。パフォーマンスはかなり安定していますが、まだ...バイナリで解析すると何が起こるかを知りたいのです。誤解しないで、私は時期尚早に最適化していません。私はdefintelyちょうど "見て"目的のためにマイクロ最適化しています。System/mscorlibのコードが非常に高速なのはなぜですか?特にループのために?
私はバイト配列を使ってテキストファイルを読み込んでいます。新しいラインは、(Windows)標準のCR/LFかCRかLFかを見つけることができます。かなり面倒です。 Array.IndexOfをCRで使用し、LFをスキップすることができるようにしたいと考えていました。代わりに、IndexOfと非常によく似たコードを書いていますが、どちらかをチェックして必要に応じて配列を返すことができます。
このように、IndexOfに非常によく似たコードを使用することで、私のコードは非常に遅くなります。
- IndexOfメソッドを使用してCRを探して::800メガバイトのファイルを使用した視点でそれを置くために〜のStreamReaderとReadLineメソッドを使用して320メガバイト/ sの
- :〜180メガバイト/ sの
- IndexOfメソッドを複製するforループ:〜150メガバイト/ S
は、ここでは、forループ(〜150メガバイト/秒)とのコードです:
IEnumerator<byte[]> IEnumerable<byte[]>.GetEnumerator() {
using(FileStream fs = new FileStream(_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, _bufferSize)) {
byte[] buffer = new byte[_bufferSize];
int bytesRead;
int overflowCount = 0;
while((bytesRead = fs.Read(buffer, overflowCount, buffer.Length - overflowCount)) > 0) {
int bufferLength = bytesRead + overflowCount;
int lastPos = 0;
for(int i = 0; i < bufferLength; i++) {
if(buffer[i] == 13 || buffer[i] == 10) {
int length = i - lastPos;
if(length > 0) {
byte[] line = new byte[length];
Array.Copy(buffer, lastPos, line, 0, length);
yield return line;
}
lastPos = i + 1;
}
}
if(lastPos > 0) {
overflowCount = bufferLength - lastPos;
Array.Copy(buffer, lastPos, buffer, 0, overflowCount);
}
}
}
}
これは高速なコードブロック(〜320メートルでありますB/S):
while((bytesRead = fs.Read(buffer, overflowCount, buffer.Length - overflowCount)) > 0) {
int bufferLength = bytesRead + overflowCount;
int pos = 0;
int lastPos = 0;
while(pos < bufferLength && (pos = Array.IndexOf<byte>(buffer, 13, pos)) != -1) {
int length = pos - lastPos;
if(length > 0) {
byte[] line = new byte[length];
Array.Copy(buffer, lastPos, line, 0, length);
yield return line;
}
if(pos < bufferLength - 1 && buffer[pos + 1] == 10)
pos++;
lastPos = ++pos;
}
if(lastPos > 0) {
overflowCount = bufferLength - lastPos;
Array.Copy(buffer, lastPos, buffer, 0, overflowCount);
}
}
(いいえ、それは生産準備ができていない、ある特定の場合には、それが爆破ようになります。私はそれらのほとんどを無視するために128kbのサイズのバッファを使用します。)
私の大きな質問は...なぜArray.IndexOfははるかに高速に動作するのですか?本質的に同じですが、forループは配列を歩いています。 mscorlibコードの実行方法については何かありますか?上記のコードを変更してIndexOfを実際に複製し、CRを探して、LFをスキップすると、IndexOfを使用しても効果はありません。 Errr ...私は様々な並べ替えを行ってきました、そして、おそらく、私は行方不明の眩しいバグがあるでしょうか?
私はReadLineを調べ、ifブロックではなくスイッチブロックを使用していることに気付きました。私が似たようなことをすると、奇妙なことに、約15mb/sほど性能が向上します。それは別の時間のためのもう一つの質問です(なぜスイッチはif?より速いのですか?)しかし、私はそれを見たと指摘しました。
また、VSの外部でリリースビルドをテストしているため、デバッグが行われていません。
うん、面白いです。反射鏡を使ってmscorlibの変種を見ると、そこにはどんなトリッキーなものが見られません。 – Joey
実際にトリッキーを使用してしまいました。 IEqualityComparer .DefaultはByteEqualityComparerを使用して終了しました。 IndexOfの既定の実装があったため、最初に気付かなかった。 Defaultプロパティをチェックすると、シェルゲームが実行され、バイトの特殊な場合にスワップされます。 –