2012-04-23 6 views
1

私は、複数のバックグラウンドスレッドからアクセスして更新/読み取りを行うリストを持っています。更新アクションには、挿入と削除の両方が含まれます。同時辞書アクセスの効率を向上させるC#

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

データを読み込むときにリストをロックする時間を最小限に抑えるために、私はそれを深くクローンしてディープクローンを返し、ディクショナリのロックを解除して更新の挿入/削除を行います。

これにより、このリストが読み込まれるたびに、私のサービスのメモリ消費が増加します。

注意点は、挿入/削除がリストを含むクラスの内部にあることです。しかし、読み物は一般消費のためのものです。

私の質問は次のとおりです。

は、どのような方法があり、私はリストをクローニング回避することができ、まだ読み取り/書き込みロックを使用して読み込むため、同時にそれを使うのか?

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(); 
       } 
      } 
     } 
    } 
+0

で動作する単一のロックを使用するすべての機能を公開し

  • 不変でなければなりませんあなたの仕事が有意義に同期されていることを確認する方法は? –

  • +0

    Ericでは、ディープコピーは、キャッシュのスナップショットとしてのみ使用されることを意図しており、変更は実際のキャッシュに反映されるべきではありません。 – EndlessSpace

    +2

    サイドノート:「時間を最小限に抑えるには...私はそれを深くクローンします」:これは「すべての悪の早期最適化ルート」が存在する正確な理由です。重要でないオブジェクトの深いクローンは速い操作であるとは考えにくいです。あなたは常にあなたの「最適化」が実際に何であるかを理解するために測定するべきです。 –

    答えて

    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ランタイムでスレッドの処理ができるようにします。

    +1

    実際、 '.Values'を返すことができます。これはcopy-on-readです。 – SLaks

    +0

    興味深い、私はそれを認識していない!それは私がそれを読んだところでは完全に意味をなさない= D – Tejs

    5

    読み取りと書き込みのロックを使用して、同時に読み取ることができます。

    しかし、ConcurrentDictionaryとスレッドセーフな不変の値を使用する方がはるかに高速で、すべての同期を取り除くことができます。

    +0

    ロックがこのクラスに対してローカルであっても、読み込みのためにロックされているオブジェクトにアクセスしていますか? – EndlessSpace

    +0

    あなたは何を意味するのか分かりません。 – SLaks

    1

    これにより、リストが読み込まれるたびに 私のサービスのメモリ消費量が増加します。

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

    あなたがコピーでやっていることは、コンカレントデータ構造(例:呼び出し時コピー・コピーが機能しますが、呼び出し元が参照を保持できない点が異なります。

    他のアプローチのカップル:

    • 戻りコレクションまでのすべての呼び出し元に同じコピーが変更されます。返されるコレクションは、呼び出し側がコピーから欲しいと独立したスレッドは、彼らの深いコピーから削除されている場合は、元のリスト

    関連する問題