7

リクエストごとに正確に1つの数値が必要な場合、ASP.NET MVCアプリケーションで乱数を生成する正しい方法は何ですか?MSDNによると、十分な品質のランダム性を得るには、一度作成された単一のSystem.Randomオブジェクトを使用して複数の数値を生成する必要があります。MVCのリクエストごとにコントローラークラスの新しいインスタンスが作成されるため、Randomオブジェクトのコントローラーのコンストラクターで初期化されたプライベートフィールドを使用できません。では、MVCアプリのどの部分にランダムオブジェクトを作成して保存する必要がありますか?現在、コントローラークラスの静的フィールドに格納し、それを使用するアクションメソッドで遅延初期化します。

public class HomeController : Controller
{
    ...

    private static Random random;

    ...

    public ActionResult Download()
    {
        ...

        if (random == null)
            random = new Random();

        ...

    }
}

「ランダム」フィールドにはコントローラークラスの複数のインスタンスからアクセスできるため、2つのインスタンスが同時に初期化しようとすると、その値が破損する可能性がありますか?そしてもう1つの質問:静力学の存続期間はアプリケーションの存続期間であることを私は知っていますが、MVCアプリの場合それは何ですか?IISの起動からIISのシャットダウンまでですか?

4

3 に答える 3

12

理想的には、Randomクラスのインスタンスを 1 つのページの有効期間よりも長く維持する必要があります。静的変数に入れてこれを行わないでください。Randomクラスはスレッドセーフではないため、問題が発生します。ドキュメントから:

インスタンス メンバーは、スレッド セーフであるとは限りません。

私のお気に入りのアプローチは、Microsoft ParallelFX チーム (スレッドで何をしているのかをよく知っている)のRandomGen2ラッパー クラスです。これは、(ほとんどの場合) ロックフリーでスレッドセーフな乱数に対してスレッドごとにインスタンスを使用します。

public static class RandomGen2 
{ 
    private static Random _global = new Random(); 
    [ThreadStatic] 
    private static Random _local;

    public static int Next() 
    { 
        Random inst = _local; 
        if (inst == null) 
        { 
            int seed; 
            lock (_global) seed = _global.Next(); 
            _local = inst = new Random(seed); 
        } 
        return inst.Next(); 
    } 
}

次のように呼び出すことができます。

var rand = RandomGen2.Next();

Randomアクセスしたい他のメソッドをラップするために追加のメソッドを追加する必要があるかもしれませんThreadSafeRandom

于 2010-05-17T07:59:10.923 に答える
3

簡単なデモか何かをまとめているのでない限り、私はこの責任をサービスまたはインフラストラクチャ レイヤー (つまり、別のクラス) に置き、乱数ジェネレーターの有効期間を管理させます。とにかく、これを管理するのは実際にはコントローラーの仕事ではありません。また、乱数を必要とする別のコントローラーがある場合でも、心配する必要はありません。

于 2010-05-17T07:51:29.037 に答える
1

HomeControllerすべてのメソッドで遅延初期化する必要がないように、静的コンストラクターを含めることができます。これにより、 が一度だけ初期化されることがほぼ保証されRandomます (最初にアクセスされたとき)。

public class HomeController : Controller
{
    ...

    private static Random random;

    static HomeController()
    {
        random = new Random();
    }

    ...

    public ActionResult Download()
    {
        ...

        //use random - its already created.


        ...

    }
}
于 2010-05-17T07:49:06.580 に答える