C#, C♯, C#相談室 Part43
■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさん
2007/09/27(木) 07:17:16前スレ
C#, C♯, C#相談室 Part42
http://pc11.2ch.net/test/read.cgi/tech/1188099745/
0153デフォルトの名無しさん
2007/10/07(日) 16:57:541文字ずつ読んで比較してもさほど時間は変わらないと思うけどな。
一度にバイト配列に読み込んでメモリに入りきらないほどのサイズだったらどうするのよ。
0154148
2007/10/07(日) 17:04:42どうしよう・・・
ってことでFileStream.ReadByte()を使って1バイトずつ
比較して合致しなかったらreturn falseっていう方法が
妥当だと考えましたがいかがでしょうか。
0155デフォルトの名無しさん
2007/10/07(日) 17:11:06BinaryReader(new BufferedStream(new FileStream(file, ...)))
0156148
2007/10/07(日) 17:11:59一バイトずつReadByte()で比較する方法を
Stopwatchクラスで計ったら1msしか違いは出ませんでした。
テストしたファイルは9118バイトで(小さいかも)378msです。
というとことは、これでReadByte()でOKかも
0157デフォルトの名無しさん
2007/10/07(日) 17:16:48>>154
別に一度に配列に全部よまなくても、「適当なサイズ」の配列に読めばいいでしょ。
どのぐらいの大きさが「適当なサイズ」かは判断が難しいところだろうけど。
実際に確認したわけじゃないけど、普通に考えればストリームがいくらバッファリング
されているからといって、配列と同じ効率でアクセスできるとは考えにくいから、
配列に一度読み出すことには意味があると思う。
それに、これも実際に確認したわけじゃないけど、
そんなことより>>152の言ってる事の方が恐らく重要。
0158デフォルトの名無しさん
2007/10/07(日) 17:19:110159デフォルトの名無しさん
2007/10/07(日) 17:30:48FileStream自体がバッファを持ってるからBufferedStreamはいらないか。
標準で8K、サイズはコンストラクタでも指定できるそうだ。
BinaryReaderは一応使っといて。
0160デフォルトの名無しさん
2007/10/07(日) 17:31:19比較にかかる時間なんて誤差の範囲
終了
0161デフォルトの名無しさん
2007/10/07(日) 18:46:17小さいの(数KB)ならいいかもしれんが。
0162デフォルトの名無しさん
2007/10/07(日) 18:48:04MD5じゃコリジョンが発生しうる
0163デフォルトの名無しさん
2007/10/07(日) 18:55:29特に問題ないからそれでいいと思うよ
0164デフォルトの名無しさん
2007/10/07(日) 19:16:260165デフォルトの名無しさん
2007/10/07(日) 19:18:520166148
2007/10/07(日) 19:22:381.5MBのテキストファイルを1バイトずつ計算したら63000msかかり
けっこう使い物にならないかも・・・
とにかく早い比較方法はないでしょうか。
MD5?調べてみます。
0167デフォルトの名無しさん
2007/10/07(日) 19:24:360168デフォルトの名無しさん
2007/10/07(日) 19:26:191対多数を比較するならMD5がいいね
0169デフォルトの名無しさん
2007/10/07(日) 19:33:25多対多ではすごく有用
0170デフォルトの名無しさん
2007/10/07(日) 19:36:03約1/2^128 あるでしょ
0171デフォルトの名無しさん
2007/10/07(日) 19:36:190172デフォルトの名無しさん
2007/10/07(日) 19:38:091対多でも有用ですよ
0173デフォルトの名無しさん
2007/10/07(日) 19:41:01>1.5MBのテキストファイルを1バイトずつ計算したら63000ms
あり得んよ。一体どんなコード書いたの?
0174デフォルトの名無しさん
2007/10/07(日) 19:47:30n回ハッシュ計算するのとn回バイト列の比較するのとどっちが効率いいと思う?
0175デフォルトの名無しさん
2007/10/07(日) 19:49:580176デフォルトの名無しさん
2007/10/07(日) 19:53:29ってか1対多って、ひとつのファイルを、複数のファイルそれぞれと比べてって話でいいんだよな?
しかしこういう時すぐにハッシュを出してくるやるはどういう発想なんだ?
多対多とかの話は別だが、単に2つのファイルの比較でもすぐに言い出すやつが出る。
0177デフォルトの名無しさん
2007/10/07(日) 19:54:540178デフォルトの名無しさん
2007/10/07(日) 19:55:53一つのファイルから1回読み込むのとn回読み込むのとどっちが効率いいと思う?
0179デフォルトの名無しさん
2007/10/07(日) 19:56:28何にもかわらんと思うが
それより、ReadByte()でバイト読みするんなら、せめてBufferedStream()
使うべきじゃね
0180デフォルトの名無しさん
2007/10/07(日) 19:58:070181デフォルトの名無しさん
2007/10/07(日) 20:01:12あふぉか?
0182デフォルトの名無しさん
2007/10/07(日) 20:02:09いらんて話がとうに出とろうがw
0183148
2007/10/07(日) 20:29:00こんなコードです。
FileStream fs1 = new FileStream(path1, FileMode.Open, FileAccess.Read);
FileStream fs2 = new FileStream(path2, FileMode.Open, FileAccess.Read);
if(fs1.Length != fs2.Length){
return false;
}
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
//How to 1
byte[] bt1 = new byte[fs1.Length];
byte[] bt2 = new byte[fs2.Length];
fs1.Read(bt1, 0, (int)fs1.Length);
fs2.Read(bt2, 0, (int)fs2.Length);
Console.WriteLine("読み出し完了" + stopWatch.ElapsedMilliseconds.ToString());
for(int i = 0; i< fs1.Length; i++){
if(bt1[i] != bt2[i]){
Console.WriteLine("見っけ"+stopWatch.ElapsedMilliseconds.ToString());
//return false;
}
}
stopWatch.Stop();
Console.WriteLine("How To 1 全部で" + stopWatch.ElapsedMilliseconds.ToString());
stopWatch.Reset();
fs1.Seek(0, SeekOrigin.Begin);
fs2.Seek(0, SeekOrigin.Begin);
0184148
2007/10/07(日) 20:29:44stopWatch.Start();
//How to 2
for (int i = 0; i < fs1.Length; i++) {
if (fs1.ReadByte() != fs2.ReadByte()) {
Console.WriteLine("見っけ" + stopWatch.ElapsedMilliseconds.ToString());
//return false;
}
}
stopWatch.Stop();
Console.WriteLine("How To 2 全部で" + stopWatch.ElapsedMilliseconds.ToString());
fs1.Close();
fs2.Close();
0185148
2007/10/07(日) 20:30:16だしたログが
>読み出し完了7ms
で7msだったのが意味わからんかったです。つまり実際byte配列には
ポインタのようなものだけ与えてるってことでしょうか。
その後は
>見っけ57491
>How To 1 全部57493
>見っけ65137
>How To 2 全部65138
って感じですけど、この全部ってのは1が早くなったり2が早くなったり
ほぼ同じくらいになったりします。
0186デフォルトの名無しさん
2007/10/07(日) 20:33:27> だしたログが
> >読み出し完了7ms
> で7msだったのが意味わからんかったです。つまり実際byte配列には
たぶんキャッシュされてるのを持ってきてる
0187デフォルトの名無しさん
2007/10/07(日) 20:35:100188デフォルトの名無しさん
2007/10/07(日) 20:37:250189デフォルトの名無しさん
2007/10/07(日) 20:39:27遅いのは毎回ストリームからLengthプロパティを取得してるからだよ。
0190デフォルトの名無しさん
2007/10/07(日) 20:44:33おいおい……
0191148
2007/10/07(日) 20:46:10確かに!!
今Lengthプロパティを変数にいれてfor文回してくるんで
ちょっと待っててください!!
0192デフォルトの名無しさん
2007/10/07(日) 20:46:140193デフォルトの名無しさん
2007/10/07(日) 20:49:530194デフォルトの名無しさん
2007/10/07(日) 20:51:330195デフォルトの名無しさん
2007/10/07(日) 20:57:07CPUがデータバスの本数を増やしてきた歴史を何だと思ってるんだよ
0196デフォルトの名無しさん
2007/10/07(日) 20:58:47なんかなかったっけ
0197148
2007/10/07(日) 21:00:35読み出し完了8
見っけ19
How To 1 全部で19
見っけ103
How To 2 全部で103
超早かったです・・・。1.5Mbの5万行のコード比較でした。
ちなみに間違った行は49999行くらいにいれてます。
この速さなら全然要望通りです。
しかもこれだと結局バイト配列に入れた方が結局早いってこと?
バイト配列ってどのくらい読み込むことできるんでしょうか。
> How To 1って
そこは触れないでください。
> 時間かかるような処理をプロパティにしないでもらいたいものだ
この50近いスレ汚しをどう償えばいいでしょうか。
0198デフォルトの名無しさん
2007/10/07(日) 21:04:22いくらバッファリングされてるといっても配列の効率に敵うはずがないって。
だからそんなことより>>152の指摘の方がずっとw
0199148
2007/10/07(日) 21:08:31>CPUがデータバスの本数を増やしてきた歴史を何だと思ってるんだよ
それはRead()メソッドのときに4バイトずつ読み込んで
byte配列[4]をuintにシフトして代入して比較するということで
合っていますか?
0200デフォルトの名無しさん
2007/10/07(日) 21:09:380201148
2007/10/07(日) 21:13:40>いくらバッファリングされてるといっても配列の効率に敵うはずがないって。
を踏まえると、配列に全部読み込んで
そこから4バイトずつでuintに代入して4バイトごと比較する!
もしくはUINT64!?
0202デフォルトの名無しさん
2007/10/07(日) 21:15:200203148
2007/10/07(日) 21:20:31コードを最適化するチェックボックスを外してたんですが
ここは関係ないですか?
0204デフォルトの名無しさん
2007/10/07(日) 23:48:07bool Hikaku(string file1, string file2)
{
using (FileStream fs1=new FileStream(file1, FileMode.Open))
using (BinaryReader br1=new BinaryReader(fs1))
using (FileStream fs2 = new FileStream(file2, FileMode.Open))
using (BinaryReader br2=new BinaryReader(fs2))
{
if (fs1.Length != fs2.Length) return false;
long num = fs1.Length / 4;
for (long i = 0; i < num; i++)
if (br1.ReadUInt32() != br2.ReadUInt32())
return false;
num = fs1.Length % 4;
for (long i = 0; i < num; i++)
if (br1.ReadByte() != br2.ReadByte())
return false;
return true;
}
}
60MBのファイルで2秒ぐらいかかった。
1バイトずつ比較しても速度が同じだったんで最適化される模様。
0205デフォルトの名無しさん
2007/10/07(日) 23:51:500206デフォルトの名無しさん
2007/10/07(日) 23:53:10バスがどうこうとかいう問題じゃないけどな。
単純に無駄な処理が多すぎるから。
Readで適当なサイズのバッファに読み込んで、
forで同じように比較してもぜんぜん変わるだろう。
ただし4バイトとかだと多分まだ無駄が多いと思う。
どのくらいがいいかはなんともいえんけど、
適当なサイズで試して、大きく改善される範囲で適当にきめたらいいだろう。
数十から数百バイト以上まとめたらもうそんなに変わらんのじゃないかな、わからんけど。
0207デフォルトの名無しさん
2007/10/07(日) 23:54:050208204
2007/10/07(日) 23:56:13ただ、メモリ食いすぎるが。
ちなみにStirlingっていうバイナリエディタのバイナリ比較を試したら3秒かかった。
0209デフォルトの名無しさん
2007/10/07(日) 23:56:280210デフォルトの名無しさん
2007/10/07(日) 23:56:570211デフォルトの名無しさん
2007/10/07(日) 23:57:11明らかにキャッシュされてるっての。
0212デフォルトの名無しさん
2007/10/07(日) 23:57:500213デフォルトの名無しさん
2007/10/07(日) 23:58:54バイナリエディタでファイルの末尾だけ弄ってるんだけどそれでもだめ?
0214デフォルトの名無しさん
2007/10/08(月) 00:00:12ってか一瞬てどれくらい?
0215デフォルトの名無しさん
2007/10/08(月) 00:04:54同じぐらいサイズの別のファイルで試してみた900�_秒ぐらい。
0216148
2007/10/08(月) 00:19:30もう一度Read()でバイト配列の比較と一バイトずつのReadByte()比較を
テストしてみたらReadByte()の方が早いという結果が出ました。
50MBのバイナリファイルで
前者が3190ms
後者が2743ms
そして204の言うとおりメモリ食いすぎなので、どっちもこれだけ早いなら
超巨大なファイルが来たときのことを考えて、
ReadByte()で1バイトずつ比較した方がいいのかも。
てかWinMergeですら同じ条件で3秒くらいかかるからもういいかなぁ
0217204
2007/10/08(月) 00:22:15これで60MBのファイルが600ミリ秒になったよ。
64KBずつ配列に読んで比較。
using (FileStream fs1=new FileStream(file1, FileMode.Open))
using (FileStream fs2 = new FileStream(file2, FileMode.Open))
{
if (fs1.Length != fs2.Length) return false;
int num = (int)fs1.Length;
byte[] data1 = new byte[num];
byte[] data2 = new byte[num];
int read;
while (true)
{
if (fs1.Position == fs1.Length) return true;
read = fs1.Read(data1, 0, 1024 * 64);
fs2.Read(data2, 0, 1024 * 64);
for (int i = 0; i < read; i++)
if (data1[i] != data2[i])
return false;
}
}
0218204
2007/10/08(月) 00:26:560219148
2007/10/08(月) 00:36:37ありがとうございますっ!
それなら最速で4GBファイルとか来ても大丈夫ですね。
それでいきたい思います。
皆様本当にありがとうございました。
0220デフォルトの名無しさん
2007/10/08(月) 00:49:460221デフォルトの名無しさん
2007/10/08(月) 00:53:35がんばってね^^
0222148
2007/10/08(月) 01:02:44すいません。20秒かかるのですが、どこか間違ってますか?
int last = (int)fs1.Length;
byte[] data1 = new byte[1024 * 64];
byte[] data2 = new byte[1024 * 64];
int read;
int sumRead = 0;
while (true) {
if (sumRead == last) {
break;
}
read = fs1.Read(data1, 0, 1024 * 64);
sumRead += read;
fs2.Read(data2, 0, 1024 * 64);
for (int i = 0; i < read; i++) {
if (data1[i] != data2[i]) {
fs1.Close();
fs2.Close();
return false;
}
}
}
0223148
2007/10/08(月) 01:05:38のコードで
if (fs1.Position == fs1.Length) return true;
は64KBごとに2つプロパティを参照するから20秒かかるかなぁ
と思ってsumReadとlastに変えてみたのですが、
変わりませんでした。
???
0224デフォルトの名無しさん
2007/10/08(月) 01:15:350225デフォルトの名無しさん
2007/10/08(月) 01:20:45なんでいきなりそんなに変わったんだ?
あ、サイズ大きくしたら逆転したってことか?
0226デフォルトの名無しさん
2007/10/08(月) 01:25:08そのコード、break後が不明なんで
勝手にreturn trueを補ったけど早かったよ。
何度やっても遅いのならキャッシュじゃない気がする。
0227148
2007/10/08(月) 01:47:27>そのコード、break後が不明なんで
>勝手にreturn trueを補ったけど早かったよ。
break後ファイルCloseしてreturn trueだけなので
変わらないと思います。
何度やっても遅かったからよくわからないです。
すいません、今日はもう限界なので明日またがんばります。
>>225
何ででしょう。結局ReadByte()ってそんなに遅くないって
ことなんでしょうか。
0228デフォルトの名無しさん
2007/10/08(月) 01:56:08それは無駄な処理が多いからであって、
バッファされないとかそういう極端な差は無い。
結局IOが重過ぎてその程度の無駄な処理は
ほとんど影響ないってことかもね。
0229デフォルトの名無しさん
2007/10/08(月) 02:02:47ReadByte()も内部ではバッファに一度4KB読み込んでその配列から1バイトずつ返している
だけみたいだから、大して遅くはならないんじゃないか。
むしろRead()の方は結構面倒くさい処理を内部でやっているっぽい。幾つかの例外処理とか
配列のコピー処理とか。
0230デフォルトの名無しさん
2007/10/08(月) 03:32:35パフォーマンス計測してて、
キャッシュをクリアしたいと思ったとき、
OS再起動してるんだ。もしくは、
メモリ量と同じサイズのファイルを読み込む
ことでもクリアと同等の意味を持つと思ってる。
もっとお手軽な方法ないのかな?
0231デフォルトの名無しさん
2007/10/08(月) 03:36:570232デフォルトの名無しさん
2007/10/08(月) 03:50:000233230
2007/10/08(月) 03:52:002回目以降のファイル読み込みが早くなるやつだ。
もっと正確にいうなら、
自作アプリのパフォーマンス計測する際に
何度か計測するが、キャッシュが効いてると
1回目と2回目以降の計測はあきらかに条件がこと
なってしまう。できるかぎり同じ条件で
計測したいってことなんだが。
良い方法ないだろうか?
0234デフォルトの名無しさん
2007/10/08(月) 04:37:460235デフォルトの名無しさん
2007/10/08(月) 10:05:341バイト比較でも配列にバッファリングしてもたいした差はでないね〜
こういう配列の比較は
for (int i = 0; i<rsize1; i++) if (buf1[i] != buf2[i]) return false;
アンセーフ使うと早くはなるのは確認
unsafe {
fixed (byte * fp1 = &buf1[0])
fixed (byte * fp2 = &buf2[0]) {
byte * p1 = fp1; byte * p2 = fp2;
for (int i = 0; i<rsize1; i++) if (*p1++ != *p2++) return false;
}}
非同期IOも使ってみたが効果なしだった
0236デフォルトの名無しさん
2007/10/08(月) 10:09:57これと同じ事かな
リンク先では解決してないっぽいね
0237デフォルトの名無しさん
2007/10/08(月) 10:26:380238デフォルトの名無しさん
2007/10/08(月) 10:27:500239デフォルトの名無しさん
2007/10/08(月) 10:42:10早くなる。
ただし末尾が余る(ことがある)ので気をつける必要がある。
0240230
2007/10/08(月) 11:39:34いや。すでにあるファイルのリード系という前提で話してるから
それは使えない。
>>236
リンク先の質問と趣旨は違ってるけど、やりたいことは同じなので
ビンゴですね。でもM$の中の人が、
>システム ファイル キャッシュだけを解放するような手段は聞いたことがありません
って書いてるので、正攻法としてはできないっぽいですね(泣
>>238
メモリクリーナー系
いまいち何やってるかわからないので敬遠してたんだ。
いろいろさんきゅー
0241デフォルトの名無しさん
2007/10/08(月) 11:47:35ほかのメモリを強制的にスワップアウトさせてる。
たぶんシステムキャッシュもクリアされるだろうけどどうかな?
0242204
2007/10/08(月) 15:04:09大体一秒で10MB処理できる感じ。
なので>>217はキャッシュが効いているみたいだね。
実際に、4GB読み込んだ後に行ったら6秒かかった。
>>222との差は環境の差なのかもしれない。
うちの環境はSATAIIのHDDに2GBのメモリです。
maxBufSize以下のファイルサイズなら一括読込。それ以上なら分割読込するようにしてみた。
仮に100MBにしてあげると60MBのファイルは2.5秒で終りました。
using (FileStream fs1 = new FileStream(file1, FileMode.Open))
using (FileStream fs2 = new FileStream(file2, FileMode.Open))
{
if (fs1.Length != fs2.Length) return false;
long last = fs1.Length;
int maxBufSize = 好きな数字を入れるだけ;
int bufsize = fs1.Length > maxBufSize ? maxBufSize : (int)fs1.Length;
byte[] data1 = new byte[bufsize];
byte[] data2 = new byte[bufsize];
int read;
long sumRead = 0;
while (true)
{
if (sumRead == last) return true;
read = fs1.Read(data1, 0, bufsize);
sumRead += read;
fs2.Read(data2, 0, bufsize);
for (int i = 0; i < read; i++)
if (data1[i] != data2[i])
return false;
}
}
0243148
2007/10/08(月) 17:06:52ありがとうございました。色々試して
自分も50MBのファイルが2.3秒くらいでできました。
これでOKです!
本当に親身になって頂きありがとうございました。
0244デフォルトの名無しさん
2007/10/08(月) 17:10:110245デフォルトの名無しさん
2007/10/08(月) 17:17:28まぁ毛の先ほども皮欄だろうが。
0246デフォルトの名無しさん
2007/10/08(月) 17:25:100247デフォルトの名無しさん
2007/10/08(月) 17:29:410248デフォルトの名無しさん
2007/10/08(月) 17:30:55比較にかかる時間なんてわずかだから
非同期にしたところでたいした違いはないと思うけどな
0249デフォルトの名無しさん
2007/10/08(月) 17:38:09って気がするよな。
そもそも単純なスループットは非同期の方が悪いんじゃなかったかな?
0250デフォルトの名無しさん
2007/10/08(月) 17:40:10どれだけシークを少なくするかにかかってるんじゃね?
0251デフォルトの名無しさん
2007/10/08(月) 17:41:130252デフォルトの名無しさん
2007/10/08(月) 18:13:16イコールの時には効率上がりそうだけど、問題はその効率を最大化するnが
環境によって大きく異なることが予想される上に計算可能性が低い(ない?)ことか?
■ このスレッドは過去ログ倉庫に格納されています