2

本当に遅いコードがあります。私はそれがそうなることを知っていました、そして今それはそうです。基本的に、私はたくさんのディレクトリからファイルを読んでいます。ファイル名は変更されますが、データは変更されません。ファイルを読み取ったかどうかを判断するために、そのバイトをハッシュし、それをすでに処理されたファイルのハッシュのリストと比較しています。各ディレクトリには約1000個のファイルがあり、各ディレクトリの新機能を把握するには1分ほどかかります(その後、処理が開始されます)。基本的なコードは次のとおりです。

public static class ProgramExtensions
{
    public static byte[] ToSHA256Hash(this FileInfo file)
    {
        using (FileStream fs = new FileStream(file.FullName, FileMode.Open))
        {
            using (SHA256 hasher = new SHA256Managed())
            {
                return hasher.ComputeHash(fs);
            }
        }
    }
    public static string ToHexString(this byte[] p)
    {

        char[] c = new char[p.Length * 2 + 2];

        byte b;

        c[0] = '0'; c[1] = 'x';

        for (int y = 0, x = 2; y < p.Length; ++y, ++x)
        {
            b = ((byte)(p[y] >> 4));

            c[x] = (char)(b > 9 ? b + 0x37 : b + 0x30);

            b = ((byte)(p[y] & 0xF));

            c[++x] = (char)(b > 9 ? b + 0x37 : b + 0x30);
        }

        return new string(c);

    }
}

class Program
{
    static void Main(string[] args)
    {
        var allFiles = new DirectoryInfo("c:\\temp").GetFiles("*.*");

        List<string> readFileHashes = GetReadFileHashes();

        List<FileInfo> filesToRead = new List<FileInfo>();

        foreach (var file in allFiles)
        {
            if (readFileHashes.Contains(file.ToSHA256Hash().ToHexString()))
                filesToRead.Add(file);
        }

        //read new files
    }
}

とにかくこれをスピードアップできますか?

4

7 に答える 7

8

最初にファイルサイズを確認するだけで、最も重要なパフォーマンスの向上をアーカイブできると思います。ファイルサイズが一致しない場合は、ファイル全体をスキップして、ファイルを開かないでください。

既知のハッシュのリストを保存するだけでなく、既知のファイルサイズのリストを保持し、ファイルサイズが一致した場合にのみコンテンツ比較を実行します。ファイルサイズが一致しない場合は、ファイルの内容を見ることさえなくて済みます。

ファイルの一般的なサイズによっては、さらに改善する価値があります。

  • 最初のバイトが異なる場合にバイナリ比較をアーリーアボートと比較する(ファイル全体の読み取りを節約できます。これは、ファイルが一般的に大きい場合に非常に大きな改善になる可能性があります。ハッシュアルゴリズムはファイル全体を読み取ります。最初のバイトが異なることを検出します。ファイルの残りの部分を読む必要がなくなります)。ルックアップファイルリストに同じサイズのファイルが多数含まれている可能性があるため、代わりに複数のファイルに対してバイナリ比較を行う必要がある場合は、次のことを検討してください。

  • それぞれ1MBのブロックでハッシュします。最初に、ルックアップで事前に計算された最初のブロックハッシュに対してのみ最初のブロックをチェックします。1番目のブロックが同じである場合にのみ2番目のブロックを比較し、ほとんどの場合、異なるファイルの1番目のブロックを超えて読み取りを保存します。これらのオプションは両方とも、ファイルが大きい場合にのみ実際に努力する価値があります。

ハッシュアルゴリズム自体を変更すること(たとえば、提案されているようにCRCを実行する最初のチェック)が大きな違いを生むとは思えません。ボトルネックはCPUではなくディスクIOである可能性が高いため、ディスクIOを回避することが最も改善されます。しかし、いつものようにパフォーマンスで、測定してください。

次に、これでも十分でない場合(そしてその場合のみ)、非同期IOを試してください(シーケンシャル読み取りは一般にランダムアクセスよりも高速であるため、ランダム非同期読み取りが多すぎるとパフォーマンスが低下する可能性があることに注意してください)

于 2009-06-09T21:52:24.073 に答える
1
  • ファイルリストを作成する
  • リストをファイルサイズで並べ替える
  • リストから一意のサイズのファイルを削除します
  • 次にハッシュを実行します(最初に高速ハッシュを実行するとパフォーマンスも向上する可能性があります)
于 2009-06-09T21:53:35.850 に答える
1
  • 効率的な検索機能(ハッシュまたはバイナリ検索)を備えたreadFileHashesストアのデータ構造を使用します。ここでは、HashSetまたはTreeSetの方が適していると思います。

  • 適切なチェックサム(ハッシュサム)関数を使用します。SHA256は、おそらくやり過ぎの暗号化ハッシュです。CRCは計算コストが低く、元々は意図しない/ランダムな変更(送信エラー)をキャッチすることを目的としていますが、非表示にするように設計/意図された変更の影響を受けやすくなっています。スキャンしているファイルの違いに合うものは何ですか?

    http://en.wikipedia.org/wiki/List_of_checksum_algorithms#Computational_costs_of_CRCs_vs_Hashesを参照してください

    サンプリングによる本当に単純なチェックサム(たとえば、チェックサム=(最初の10バイトと最後の10バイト))は機能しますか?

于 2009-06-09T22:15:15.353 に答える
0

安価なので、最初に簡単なCRCハッシュチェックを行います。CRCが一致しない場合は、SHAなどのより「信頼性の高い」ハッシュテストを続行します

于 2009-06-09T21:47:19.110 に答える
0

問題の説明はまだ十分に明確ではありません。

最大の問題は、大量のハッシュを実行していることです。これは遅いことが保証されています。

ファイル名が変更されても変更されない変更時刻を検索してみてください。

http://msdn.microsoft.com/en-us/library/ms724320(VS.85,loband).aspx

または、新しいファイルの変更がないかフォルダを監視することもできます。

http://www.codeguru.com/forum/showthread.php?t=436716

于 2009-06-09T22:13:32.690 に答える
0

まず、ファイルをファイルサイズでグループ化します。これにより、ファイルのグループが小さくなります。現在、それはグループサイズとファイルサイズに依存します。違いが見つかるまで、すべてのファイルを並行して読み取り始めることができます。違いがある場合は、グループを現在の位置で同じ値を持つ小さなグループに分割します。ファイルの違いに関する情報がある場合は、この情報を使用できます。最後から読み取りを開始し、クラスターが大きく変更された場合はバイトごとに読み取ったり比較したりしないでください。ファイルについて知っていることは何でもかまいません。このソリューションでは、多数のファイルを並行して読み取る必要があり、ランダムなディスクアクセスが発生する場合に、I/Oパフォーマンスの問題が発生する可能性があります。

各グループのすべてのファイルのハッシュ値を計算して比較することもできます。ファイル全体を一度に処理する必要はありません。数バイト(おそらく4kiBクラスターまたはファイルサイズに合うもの)のハッシュを計算し、すでに違いがあるかどうかを確認してください。そうでない場合は、次の数バイトのハッシュを計算します。これにより、メモリ内のグループ内のファイルごとに1つの大きなブロックを保持する必要なしに、各ファイルの大きなブロックを処理できるようになります。

つまり、時間メモリ(ディスクI / Oメモリ)のトレードオフがすべてです。グループ内のすべてのファイルをメモリに読み込んでバイトごとに比較する方法(メモリ要件が高く、高速シーケンシャルアクセスですが、多くのデータを読み取る可能性があります)と、ファイルをバイトごとに読み取って最後のバイトのみを比較する方法を見つける必要があります。読み取り(メモリ要件が低く、ランダムアクセスが遅く、必要なデータのみを読み取ります)。さらに、グループが非常に大きい場合、ファイルをバイトごとに比較すると遅くなります(n個のファイルから1バイトを比較するのはO(n)操作です)。最初にハッシュ値を計算してから、ハッシュのみを比較する方が効率的になる可能性があります。値。

于 2009-06-09T22:33:28.000 に答える
0

更新:ファイルサイズの唯一のチェックは絶対に行わないでください。お使いのOSバージョンでFileInfo.LastWriteTimeの使用が許可されている場合

社内のプロジェクトコンパイラ/パッケージャに似たようなものを実装しました。8kを超えるファイルがあるため、最終変更日とハッシュデータをSQLデータベースに保存します。その後の実行では、最初に特定のファイルの変更日に対してクエリを実行し、次にハッシュデータに対してクエリを実行します...このようにして、変更されたように見えるファイルの新しいハッシュデータのみを計算します...

.netには、FileInfoクラスで最終変更日を確認する方法があります。確認することをお勧めします。編集:ここにリンクLastWriteTimeがあります

パッケージャーは、変更されたファイルを見つけるのに約20秒かかります。

于 2009-06-09T23:22:59.400 に答える