2

ASP.NET MVC アプリケーションを作成していますが、起動時にマルチスレッドの問題が発生する可能性があるのではないかと心配しています。特に懸念されるのは、次のコードです。

private static IDictionary<string, ISettings> _settingsDictionary = new Dictionary<string, ISettings>();

public T Settings<T>() where T : ISettings, new() {
    var key = typeof(T).FullName;

    if (!_settingsDictionary.ContainsKey(key))
        _settingsDictionary[key] = _settingsService.GetSettings<T>();

    return (T)_settingsDictionary[key];
}

ディクショナリが静的として定義されていることに注意してください。これにより、ディクショナリをキャッシュして、アプリケーションの長さのすべてのリクエストに対して同じインスタンスを返すことができます。

これは、ローカルでテストする場合は問題なく機能しますが、何百人ものユーザーが使用すると問題が発生する可能性があるのではないかと心配しています. これにより、ConcurrencyDictionary を調査するようになりました。使用する必要があるかどうか、また使用する場合はどのようにすればよいか教えてください。

ありがとう

4

2 に答える 2

6

はい、潜在的なデータ競合がここにあります:

if (!_settingsDictionary.ContainsKey(key))
    _settingsDictionary[key] = _settingsService.GetSettings<T>();

いつでも中断される可能性があるため、2 つのスレッドが同じキーを追加する可能性があります。

代わりにConcurrentDictionary.GetOrAddを使用できます。

private static ConcurrentDictionary<string, ISettings> _settingsDictionary = new ConcurrentDictionary<string, ISettings>();

public T Settings<T>() where T : ISettings, new() {
    var key = typeof(T).FullName;

    return _settingsDictionary.GetOrAdd(key, _settingsService.GetSettings<T>());
}

編集_settingsService.GetSettings<T>():毎回実行したくないので、代替手段は次のとおりです。

private static IDictionary<string, ISettings> _settingsDictionary = new Dictionary<string, ISettings>();
private static object locker = new object();

public T Settings<T>() where T : ISettings, new() {
    var key = typeof(T).FullName;
    lock(locker) 
    {
        if (!_settingsDictionary.ContainsKey(key))
            _settingsDictionary[key] = _settingsService.GetSettings<T>();

        return (T)_settingsDictionary[key];
    }
}
于 2012-08-29T10:50:29.753 に答える
2

はい、次の場所にキーが見つからない場合、競合が発生します。

if (!_settingsDictionary.ContainsKey(key))

次に、実行するまでに:

_settingsDictionary[key] = _settingsService.GetSettings<T>();

鍵があるかもしれません。

不必要に交換するよりもさらに悪いことです。スレッド 1 がキーを追加するときにサイズ変更が必要な場合、スレッド 2 が追加する途中でサイズ変更が必要と見なされる可能性があり、そのディクショナリをそれ以上使用することはほとんどありません。

重要な問題は、「これは、多数のスレッドが同時に辞書にヒットする期間がある場合ですか、それとも、まれではあるが、それを防ぐ必要がある場合ですか?」ということです。

最初のケースでは、ConcurrentDictionary を使用します。2 番目のケースでは、現在のコードにロックを追加するだけです。ConcurrentDictionary は (名前から予想されるように) 同時実行性に直面してより優れたパフォーマンスを提供しますが、実際にヒットするスレッドが通常 1 つしかない場合、通常のディクショナリの周りのロックの方が優れていますが、時折の同時呼び出しが可能です。

両方の代わりに、可能な設定の数が少ない場合は、最初にロットをロードするだけです。ディクショナリは、書き込みがなければ複数のリーダーにとって安全であり、ロックがゼロの場合は最も高速です。

于 2012-08-29T11:15:54.323 に答える