リモートサイトに(ネットワークで)接続し、一般的なリストを返す複数の関数を実行しようとしています。しかし、私はそれらを同時に実行したい。
例えば:
public static List<SearchResult> Search(string title)
{
//Initialize a new temp list to hold all search results
List<SearchResult> results = new List<SearchResult>();
//Loop all providers simultaneously
Parallel.ForEach(Providers, currentProvider =>
{
List<SearchResult> tmpResults = currentProvider.SearchTitle((title));
//Add results from current provider
results.AddRange(tmpResults);
});
//Return all combined results
return results;
}
私が見るように、「結果」への複数の挿入が同時に発生する可能性があります...これは私のアプリケーションをクラッシュさせる可能性があります。
どうすればこれを回避できますか?
//In the class scope:
Object lockMe = new Object();
//In the function
lock (lockMe)
{
results.AddRange(tmpResults);
}
基本的にロックとは、1つのスレッドのみが同時にそのクリティカルセクションにアクセスできることを意味します。
同時収集 を使用できます。
System.Collections.Concurrent
名前空間は、複数のスレッドが同時にコレクションにアクセスするときはいつでも、System.Collections
名前空間とSystem.Collections.Generic
名前空間の対応する型の代わりに使用するいくつかのスレッドセーフコレクションクラスを提供します。
たとえば、 ConcurrentBag
を使用できます。これは、アイテムが追加される順序を保証できないためです。
オブジェクトのスレッドセーフで順序付けられていないコレクションを表します。
コンカレントコレクションは、.Net 4の新機能です。新しい並列機能と連携するように設計されています。
。NET Framework 4の同時コレクション を参照してください:
.NET 4以前は、複数のスレッドが単一の共有コレクションにアクセスする可能性がある場合、独自の同期メカニズムを提供する必要がありました。コレクションをロックする必要がありました...
... System.Collections.Concurrent [.NET 4に追加]の[新しい]クラスとインターフェイスは、スレッド間の共有データに関連する[...]マルチスレッドプログラミング問題の一貫した実装を提供します。
コードを好む人向け:
public static ConcurrentBag<SearchResult> Search(string title)
{
var results = new ConcurrentBag<SearchResult>();
Parallel.ForEach(Providers, currentProvider =>
{
results.Add(currentProvider.SearchTitle((title)));
});
return results;
}
これは、PLINQのAsParallel
およびSelectMany
を使用して簡潔に表現できます。
public static List<SearchResult> Search(string title)
{
return Providers.AsParallel()
.SelectMany(p => p.SearchTitle(title))
.ToList();
}