1

InstanceContextMode=SingleおよびConcurrencyMode=Multipleでタグ付けされた単純なWCFサービスがあります。リストを返すメソッドの場合、データベースにアクセスして呼び出しが行われたときにリストに入力するのではなく、リストのローカルコピーを返すだけです。リストは、24時間ごとにデータベースに送信され、リストを再作成するバックグラウンドスレッドによって維持されます。並行性の問題は、コレクションを返すメソッド内とコレクションを埋めるメソッド内の2か所でオブジェクトをロックすることで処理します。

私の質問は、どうすればこれをより効率的にすることができるかということです。現在、クライアントが呼び出すアウトサービスメソッド「GetCustomers」にボトルネックがあります。

public List<ZGpCustomer> GetCustomers()
{
    List<ZGpCustomer> customerListCopy = new List<ZGpCustomer>();
    lock (_customerLock)
    {
        customerListCopy = new List<ZGpCustomer>(_customers);
    }

    return customerListCopy;
}

「_customers」は24時間ごとにのみ入力されるため、コレクションを変更する場合にのみ、GetCustomersメソッド内でロックする必要があるだけのようです。現在の設定方法では、1000個のリクエストが同時に着信した場合、一度に1つのスレッドのみがそのメソッドにアクセスできるため、1000個のリクエストを効果的にキューに入れています。これにより、サービスのマルチスレッドの側面がやや役に立たなくなりますね。

この種のパターンのベストプラクティスはありますか?オブジェクトを保存するために、より適切なデータ収集を使用する必要がありますか?「BlockingCollection」の方が適していますか?

4

1 に答える 1

2

これを行うためのより効率的な方法が確かにあります。秘訣は、コレクションへのマスター参照を不変に保つことです。そうすれば、リーダー側でアクセスを同期する必要がなくなります。物事のライター側だけがロックを必要とします。リーダー側は何も必要としません。つまり、リーダーは高度な同時実行性を維持します。あなたがする必要がある唯一のことは、_customers参照を揮発性としてマークすることです。

// Variable declaration
object lockobj = new object();
volatile List<ZGpCustomer> _customers = new List<ZGpCustomer>();

// Writer
lock (lockobj)
{
  // Create a temporary copy.
  var copy = new List<ZGpCustomer>(_customers);

  // Modify the copy here.
  copy.Add(whatever);
  copy.Remove(whatever);

  // Now swap out the references.
  _customers = copy;
}

// Reader
public List<ZGpCustomer> GetCustomers()
{
    return new List<ZGpCustomer>(_customers);
}

の署名をGetCustomers少し変更したい場合は、の不変性を利用し_customersて読み取り専用ラッパーを返すことができます。

// Reader
public IList<ZGpCustomer> GetCustomers()
{
    return _customers.AsReadOnly();
}
于 2012-04-05T14:04:21.780 に答える