1

更新/読み取りのために複数のバックグラウンドスレッドからアクセスされるリストがあります。更新アクションには、挿入と削除の両方が含まれます。

同期の問題なしにこれを同時に行うために、クラス内のプライベート読み取り専用オブジェクトのロックを使用しています。

データを読み取るときにリストをロックする必要がある時間を最小限に抑えるために、リストのディープクローンを作成し、ディープクローンを返し、更新の挿入/削除のためにディクショナリのロックを解除します。

このため、リストを読み取るたびに、サービスのメモリ消費量が増加します。

注意すべき点の1つは、挿入/削除はリストを含むクラスの内部にあるということです。しかし、読み取りは一般消費を目的としています。

私の質問は:

リストのクローンを作成せずに、読み取り/書き込みロックを使用した読み取りに同時に使用する方法はありますか?

public class ServiceCache
    {
        private static List<Users> activeUsers;
        private static readonly object lockObject = new object();
        private static ServiceCache instance = new ServiceCache();

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

        private void AddUser(User newUser)
        {
            lock (lockObject)
            {
                //... add user logic
            }
        }

        private void RemoveUser(User currentUser)
        {
            lock (lockObject)
            {
                //... remove user logic
            }
        }

        public List<Users> ActiveUsers
        {
            get
            {
                lock (lockObject)
                {
                    //The cache returns deep copies of the users it holds, not links to the actual data.
                    return activeUsers.Select(au => au.DeepCopy()).ToList();
                }
            }
        }
    }
4

3 に答える 3

6

クラスを使用して、保存しているオブジェクトConcurrentDictionaryごとにキーを作成する必要があるようです。Users次に、ユーザーを追加/更新するのは次のように簡単になります。

_dictionary.AddOrUpdate("key", (k, v) =>
    {
        return newUser;
    }, (k, v) =>
    {
        return newUser;
    });

そして、削除するには、次のようにします。

 Users value = null;
_dictionary.TryRemove("key", out value);

次のことを行うだけでよいので、人のリストを取得するのも非常に簡単です。

return _dictionary.Values.Select(x => x.Value).ToList();

その瞬間に辞書の内容のコピーを返すはずです。

そして、.NETランタイムにスレッド化を任せましょう。

于 2012-04-23T19:48:01.780 に答える
5

リーダーライターロックを使用して、同時読み取りを許可できます。

ConcurrentDictionaryただし、スレッドセーフな不変の値を使用してから、すべての同期を削除する方がはるかに高速です。

于 2012-04-23T19:47:20.557 に答える
1

このため、リストを読み取るたびに、サービスのメモリ消費量が増加します。

なんで?発信者は参照を解放していませんか?辞書の内容は変わる可能性があるので、そうする必要があります。

コピーで行っていることは、呼び出し元が参照を保持できないことを除いて、コピーオンライトコレクションなどの同時データ構造がどのように機能するかに非常に近いと思います。

他のいくつかのアプローチ:

  • コレクションが変更されるまで、すべての呼び出し元に同じコピーを返します。返されるコレクションは不変である必要があります

  • 呼び出し元がコピーから必要とするすべての機能を公開し、単一のロックを使用して元のリストを操作します

于 2012-04-23T20:07:34.350 に答える