0

非常に大きなルックアップ テーブルを使用して数学的計算を高速化するアプリを開発しています。これらのテーブルの最大のものは、約 1,000 万のエントリを持つ int[] です。すべてのルックアップ テーブルが int[] であるわけではありません。たとえば、1 つは ~200,000 エントリの辞書です。現在、各ルックアップ テーブルを 1 回 (数分かかります) 生成し、次のスニペットを使用して (圧縮して) ディスクにシリアル化します。

    int[] lut = GenerateLUT();
    lut.Serialize("lut");

Serialize は次のように定義されます。

    public static void Serialize(this object obj, string file)
    {
        using (FileStream stream = File.Open(file, FileMode.Create))
        {
            using (var gz = new GZipStream(stream, CompressionMode.Compress))
            {
                var formatter = new BinaryFormatter();
                formatter.Serialize(gz, obj);
            }
        }
    }

アプリケーションを起動するときに私が悩まされているのは、これらのルックアップ テーブルの逆シリアル化に非常に長い時間がかかることです (15 秒以上)。このタイプの遅延は、すべてのルックアップ テーブルが読み込まれるまでアプリが使用できなくなるため、ユーザーを悩ませます。現在、デシリアライゼーションは次のとおりです。

     int[] lut1 = (Dictionary<string, int>) Deserialize("lut1");
     int[] lut2 = (int[]) Deserialize("lut2");
 ...

ここで、Deserialize は次のように定義されます。

    public static object Deserialize(string file)
    {
        using (FileStream stream = File.Open(file, FileMode.Open))
        {
            using (var gz = new GZipStream(stream, CompressionMode.Decompress))
            {
                var formatter = new BinaryFormatter();
                return formatter.Deserialize(gz);
            }
        }
    }

最初は、速度低下の原因は gzip 圧縮ではないかと考えていましたが、それを削除してもシリアライゼーション/デシリアライゼーション ルーチンから数百ミリ秒しかスキミングされませんでした。

アプリの初回起動時にこれらのルックアップ テーブルの読み込み時間を短縮する方法を提案できる人はいますか?

4

5 に答える 5

2

まず、バックグラウンドスレッドで逆シリアル化すると、これが発生している間、アプリが「ハング」するのを防ぐことができます。それだけで問題を解決できるかもしれません。

ただし、一般に、シリアル化と逆シリアル化(特に大きな辞書の場合)は非常に遅くなる傾向があります。データ構造によっては、独自のシリアル化コードを作成すると、特にデータ構造に共有参照がない場合に、これを大幅に高速化できます。

そうは言っても、これの使用パターンによっては、データベースの方が良いアプローチかもしれません。いつでもデータベース指向の何かを作成し、DBから怠惰な方法でルックアップテーブルを構築できます(つまり、ルックアップはLUTでのルックアップですが、ルックアップが存在しない場合は、DBからロードして保存します)テーブルにあります)。これにより、(少なくともLUTに関しては)起動が瞬時に行われ、ルックアップがかなり迅速に保たれる可能性があります。

于 2009-07-21T00:02:10.740 に答える
0

もう1つのオプションは、テーブルを実際のデータベーステーブルというテーブルに配置することです。Accessのようなエンジンでも、すべてのクエリに明確なインデックスがあるため、かなり良いパフォーマンスが得られるはずです。これで、アプリは実際にデータを使用しようとしているときにのみデータを読み込む必要があり、それでもファイル内のどこを見ればよいかを正確に知ることができます。

これにより、計算ごとにディスク読み取りを実行する必要があるため、アプリの実際のパフォーマンスが少し低下する可能性があります。しかし、長い待ち時間がないため、アプリのパフォーマンスが大幅に向上します。そして、好むと好まざるとにかかわらず、知覚はおそらく現実よりも重要です。

于 2009-07-21T00:08:21.973 に答える
0

ここで話しているデータの量はどれくらいですか?私の経験では、ディスクからメモリにギガバイトを読み取るのに約20秒かかります。したがって、0.5ギガバイト以上を読んでいる場合は、ほぼ確実にハードウェアの制限に直面しています。

データ転送速度が問題ではない場合、実際の逆シリアル化には時間がかかります。十分なメモリがある場合は、(を使用してFile.ReadAllBytes())すべてのテーブルをメモリバッファにロードしてから、メモリストリームから逆シリアル化できます。これにより、読み取りにかかる時間と、逆シリアル化にかかる時間を判別できます。

逆シリアル化に時間がかかる場合は、複数のプロセッサがある場合は、複数のスレッドを生成して並列化を実行できます。このようなシステムでは、別のテーブルのデータをロードしているときに、1つ以上のテーブルを逆シリアル化する可​​能性があります。このパイプライン化されたアプローチにより、ロード/デシリアライズ時間全体がロードのみとほぼ同じくらい速くなる可能性があります。

于 2009-07-21T00:05:25.617 に答える
0

なぜそれらを圧縮するのですか?

ディスクはRAMよりも大きいです。

ストレートバイナリ読み取りはかなり速いはずです。

于 2009-07-21T00:26:56.167 に答える
0

明らかな提案は、それらをバックグラウンドでロードすることだと思います。アプリが起動し、ユーザーがプロジェクトを開き、必要な操作を選択すると、15 秒ほど待つ必要はありません。

于 2009-07-20T23:53:37.167 に答える