同時実行するときのコレクション

以下を実行すると、ArgumentException になったり result が歯抜けになったりする。

var result = new Dictionary<int, int>();

Parallel.For(0, 10000, i =>
{
    result.Add(i, CalculateSomething(i););
});

これは Dictionary がスレッドセーフでないため。 ConcurrentDictionary を使おう。

var result = new ConcurrentDictionary<int, int>();

Parallel.For(0, 10000, i =>
{
    result.Add(i, CalculateSomething(i););
});

List であれば ConcurrentBag になる。 Visual Studio のサジェストから CuncurrentList 的なものを必死で探しても見つからないので注意。

var result = new ConcurrentBag<int>();

Parallel.For(0, 10000, i =>
{
    result.Add(CalculateSomething(i););
});

同時実行時の実行結果がコレクションのコレクションとして格納したい場合があるが ConcurrentBag には AddRange が無い。拡張メソッドを書いてやる。

public static void AddRange<T>(this ConcurrentBag<T> @this, IEnumerable<T> collection)
{
    foreach (var element in collection)
    {
        @this.Add(element);
    }
}

これを使ってこう。

var result = new ConcurrentBag<IEnumerable<int>>();

Parallel.For(0, 10000, i =>
{
    result.AddRange(GetNumbers(i););
});