3

データベースからフェッチされたものに基づいて計算するために、かなりの量のリクエストで使用する数千の整数のルックアップ テーブル (LUT) があります。

単純に LUT を保持するための標準的なシングルトンを作成した場合、それはリクエスト間で自動的に永続化されますか?それとも特にアプリケーション状態にプッシュする必要がありますか?

それらが自動的に永続化される場合、それらをアプリケーション状態で保存する違いは何ですか?

正しいシングルトンの実装はどのようになりますか? 遅延初期化する必要はありませんが、スレッド セーフ (サーバー インスタンスあたり数千の理論上のユーザー) であり、優れたパフォーマンスを備えている必要があります。

編集: Jon Skeet の 4 番目のバージョンは有望に見えます http://csharpindepth.com/Articles/General/Singleton.aspx

public sealed class Singleton
{
    static readonly Singleton instance=new Singleton();

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    static Singleton()
    {
    }

    Singleton()
    {
    }

    public static Singleton Instance
    {
        get
        {
            return instance;
        }
    }

    // randomguy's specific stuff. Does this look good to you?
    private int[] lut = new int[5000];

    public int Compute(Product p) {
        return lut[p.Goo];
    }
}
4

3 に答える 3

2

はい、静的メンバーは永続化されます (永続化されたものとは異なります。「保存」されず、消えることはありません)。これには、シングルトンの実装が含まれます。静的割り当てまたは静的コンストラクターで作成されたかのように、ある程度の遅延初期化を無料で取得できます。関連するクラスが最初に使用されるまで呼び出されません。その作成はデフォルトでロックされますが、他のすべての使用は、あなたが言うようにスレッドセーフでなければなりません。関与する同時実行性の程度を考えると、シングルトンが不変になる場合 (ルックアップ テーブルはアプリケーションの有効期間中変更されない) でない限り、それを更新する方法について非常に注意する必要があります (1 つの方法は偽のシングルトンです)。 - 更新時に新しいオブジェクトを作成し、それを割り当てて現在の値を置き換えることをロックします。厳密にはシングルトンではありませんが、1 つのように見えますが、"

特に Web のようなステートレス プロトコルを扱う場合、グローバル ステートを導入するものはすべて疑わしいという大きな危険があります。ただし、特に永続的またはほぼ永続的なデータのメモリ内キャッシュとして、特にデータベースから簡単にすばやく取得できないオブジェクトグラフが含まれる場合に、うまく使用できます。

ただし、落とし穴がかなりあるので、注意してください。特に、ロックの問題のリスクは軽視できません。

編集、質問の編集と一致するように:

私の大きな懸念は、配列がどのように初期化されるかです。明らかに、この例は各項目に対して 0 しかないため、不完全です。初期化時に設定され、読み取り専用であれば問題ありません。変更可能な場合は、スレッド化に非常に注意してください。

また、このようなルックアップが多すぎるとスケーリングに悪影響が及ぶことにも注意してください。事前計算を行うことでほとんどのリクエストを節約できますが、その結果、シングルトンが更新されるときに非常に重い作業の期間が発生します。起動に時間がかかることはおそらく許容できますが (それほど頻繁ではないため)、その後に発生する任意の速度低下は、その原因を突き止めるのが難しい場合があります。

于 2010-08-12T01:10:54.263 に答える
2

リクエスト間で静的が保持されることに依存しません。[可能性は低いですが、リクエスト間でプロセスがリセットされる可能性は常にあります。] リクエスト間で共有リソースを保持するには、HttpContext の Cache オブジェクトをお勧めします。

于 2010-08-12T00:25:56.263 に答える
0

編集: 読み取り専用ロックに関する Jon のコメントを参照してください。

シングルトンを扱ってからしばらく経ちましたが (IOC コンテナーにライフタイムを処理させることを好みます)、スレッド セーフの問題を処理する方法を次に示します。シングルトンの状態を変更するものはすべてロックする必要があります。Compute(int)ロックする必要がないなどの読み取り専用操作。

// I typically create one lock per collection, but you really need one per set of atomic operations; if you ever modify two collections together, use one lock.
private object lutLock = new object();
private int[] lut = new int[5000];

public int Compute(Product p) {
    return lut[p.Goo];
}

public void SetValue(int index, int value)
{
    //lock as little code as possible. since this step is read only we don't lock it.
    if(index < 0 || index > lut.Length)
    {
        throw new ArgumentException("Index not in range", "index");
    }
    // going to mutate state so we need a lock now
    lock(lutLock)
    {
        lut[index] = value;
    }
}
于 2010-08-12T03:39:39.640 に答える