web-dev-qa-db-ja.com

ソケットがメッセージを受信して​​いる間、オブジェクトのリストをロックする必要がありますか?

ソケット接続を介してメッセージを受信するシナリオがあります。また、100個のメッセージ(リストなど)のリストを保持し、条件が満たされたときにリストから古いメッセージを定期的に破棄する必要があります。

List<Message> MessageList = new List<Message>();
Message CurrentMessage = new Message();

public void ReceiveSocketMessage (SocketMessage Message) {

    if (Message.Type == duplicate) {
        CurrentMessage = MessageList.FirstOrDefault(x=> x.MessageText == Message.Text);
        CurrentMessage.Time = DateTime.Now;
    } else {
        MessageList.Add(Message);
    }
}

ソケットはメッセージを非常に高速に送信するため、MessageListにアクセスしようとする他のメソッドが問題を引き起こすようです。他の方法では、ランダムな時点でリストにアクセスする必要があります。

問題を起こさずにオブジェクトのリストで作業することに頭を悩ませることはできません。これを処理する従来の方法は何ですか?

更新:c#オブジェクトのリストではなく、データベーステーブル内のアイテムのリストを維持する方が簡単でしょうか?データベースには確かに、私がそれについて心配する必要がないところまで、すべての主要なロックの問題が解決されているでしょう。

2
osoclever

ここでの指針となる要素は、キューを通過すると予想されるトラフィックの量、その重要性、および読み取りと書き込みの関係です。

.Netフレームワークには、並行処理を支援し、多くの時間と労力を節約できる非常に便利な組み込みコレクションがいくつかありますが、もちろん、リソースのロックとロック解除を試してみると、ほぼ確実にあいまいなものにぶつかることになります。遅かれ早かれ状況をブロックします。確かに、ConcurrentQueueまたは同様のものは、あなたが概説した問題を解決するのに役立つはずです。もちろん、キューはプッシュポップタイプのワークフローを期待します。これはあなたが望むものかもしれませんが、そうでない場合は、他の スレッドセーフコレクション を調べるのに役立つかもしれません。

これらが本質的に「受信」キューに入れて処理する必要がある着信メッセージである場合は、単にデータベースにデータをドロップするのではなく、何らかのメッセージキューを使用することを検討できます。これにより、次の利点が得られます。システムがダウンした場合に回復可能であるようにキューデータを保存し(これは重要な場合と重要でない場合があります)、将来的にワークロードを分散する必要がある場合は、他のクライアントを接続するだけでよいことも意味します。キューに入れ、必要に応じて処理します。あなたを助けることができるかもしれないたくさんのメッセージキューツールがそこにあります、しかし明らかにこれの必要性はあなたの文脈にかなり依存しています。

1
glenatron

標準リストをカスタムリストクラスにカプセル化します。これはスレッドセーフになります。スレッドセーフに到達する方法は適切にカプセル化されており、通常の使用法を前提として、実装を微調整して最高のパフォーマンスを実現できます。

最初に、リストへのすべてのアクセスを単純にロックするだけで許容できるパフォーマンスが得られるかどうかを試してください。もしそうなら、あなたは完了です!

これが遅すぎる場合は、リストの使用状況をプロファイリングする必要があります。複数のスレッドからの読み取りが多く、書き込みが少ないですか? ReaderWriterLockを試すことができます。これにより、読み取りを並行して実行できます。また、一括更新を行うためのバッファリングもあります。これにより、書き込みロック時間が最小限に抑えられます。

1
Bgie