3

だから、私は ConcurrentDictionary に甘やかされてきましたが、それは素晴らしいTryGetValue方法です。ただし、通常の Dictionary のみを使用するように制限されています。これは、携帯電話やその他のプラットフォームを対象とするポータブル クラス ライブラリに含まれているためです。Dictionary の非常に限られたサブセットを作成し、それをスレッドセーフな方法で公開しようとしています。

基本的にGetOrAdd、ConcurrentDictionary のようなものが必要です。現在、私はこれを次のように実装しています:

        lock (lockdictionary)
        {
            if (!dictionary.ContainsKey(name))
            {
                value = new foo();
                dictionary[name] = value;
            }
            value = dictionary[name];
        }

これは基本的に私が手に入れることができるのと同じくらい良いですか?キーが存在せず、追加された場合にのみロックが必要だと思いますが、「存在する場合は値を取得し、それ以外の場合は null を返す」という適切な方法はありませんContainsKey ビットを省略した場合、キーが存在しない場合、キーが存在しないために例外が発生します。

とにかくこれをより無駄のないバージョンにすることはできますか? それとも、これは通常の辞書でできる最善のことですか?

4

5 に答える 5

2

並行ライターが存在する場合の読み取りでも、ロックが必要です。そうです、これは、辞書を変更した場合と同じくらい優れています。

もちろん、何かが書かれるたびに辞書全体のコピーをいつでも作成できます。そうすれば、読者は古いバージョンを目にするかもしれませんが、安全に読むことができます。

于 2013-02-26T17:03:47.640 に答える
1

を使用してみることができReaderWriterLockSlimます。例えば:

ReaderWriterLockSlim locker = new ReaderWriterLockSlim();

//..

public string GetOrAdd(string name)
{
    locker.EnterUpgradeableReadLock();
    try
    {
        if(!dictionary.ContainsKey(name))
        {
            locker.EnterWriteLock();
            try
            {
                dictionary[name] = new foo();
            }
            finally
            {
            locker.ExitWriteLock();
            }
        }
        value = dictionary[name];
    }
    finally
    {
        locker.ExitUpgradeableReadLock();
    }
    return value;
}
于 2013-02-26T17:13:09.727 に答える
0

あなたの実装は問題ありません。競合しないアクセスの場合、ロックの実装によるパフォーマンスの低下は無視できることに注意してください。ただし、真のスレッドセーフを実現するには、辞書を使用したすべての操作でロックを使用する必要があります-SynchronizedDictinory同期ロジックを1か所に保持するなど、ラッパークラスを作成することをお勧めします

于 2013-02-26T17:07:11.743 に答える
0

これはそれが得られるのと同じくらい良いです。

ディクショナリは、更新と読み取りを並行して実行できることをまったく保証しないため、ロックが必要です。内部データ構造への変更が原因で、他のスレッドでの更新と同時に実行されている要素を取得するための単一の呼び出しでも失敗する場合があります。

この動作は、Dictionaryの Thread Safety セクションで明示的にカバーされていることに注意してください。

コレクションが変更されない限り、ディクショナリは複数のリーダーを同時にサポートできます。それでも、コレクションの列挙は本質的にスレッドセーフな手順ではありません。列挙が書き込みアクセスと競合するまれなケースでは、列挙全体の間、コレクションをロックする必要があります。読み取りおよび書き込みのために複数のスレッドがコレクションにアクセスできるようにするには、独自の同期を実装する必要があります。

于 2013-02-26T17:04:51.583 に答える
0

次のように、ダブルチェック パターンを使用できます。

if (!dictionary.ContainsKey(name))
{
    lock (lockdictionary)
    {
        if (!dictionary.ContainsKey(name))
        {
            value = new foo();
            dictionary[name] = value;
        }
        value = dictionary[name];
    }
}

これにより、実際に必要な場合にのみロックすることが保証されますが、ロックした後でも値を追加する必要があることも保証されます。パフォーマンスは、常にロックするよりも優れているはずです。しかし、私の言葉を鵜呑みにしないでください。テストを実行してください!

于 2013-02-26T17:27:04.540 に答える