.NET Framework 4 になり Task Parallel Library (TPL) が追加され,並列処理が容易に行えるようになりました。
並列プログラミングでよく用いられるパターンに producer-consumer パターンがあります。 TPL を用いた producer-consumer の例を紹介します。
var random = new Random();
var queue = new ConcurrentQueue<Person>();
bool closed = false;
int proceeds = 0;
Action producer = () =>
{
do
{
int money;
lock (random)
{
money = random.Next(1000, 10000);
if (random.NextDouble() > 0.99)
{
closed = true;
}
}
Person customer = new Person() { PocketMoney = money };
queue.Enqueue(customer);
} while (!closed);
};
Action consumer = () =>
{
Person customer;
while (!closed || !queue.IsEmpty)
{
if (queue.TryDequeue(out customer))
{
int take;
lock (random)
{
take = random.Next(customer.PocketMoney);
}
Interlocked.Add(ref proceeds, take);
}
}
};
Parallel.Invoke(producer, consumer, consumer);
Console.WriteLine("売上金: {0:#,0}円", proceeds);
class Person
{
public int PocketMoney { get; set; }
}
producer は顧客が待ち行列を作って店に並ぶイメージです。 consumer は顧客に応対してポケットマネーを頂戴します。最終的に consumer が稼いだ金額の合計をコンソールに出力します。ここでは 1-producer-N-consumer の例を示していますが,もちろん 1-1 や N-N に対応することも容易です。
この例では ConcurrentQueue クラスを用いていますが,他にもいくつかのスレッドセーフなコレクションが System.Collections.Concurrent 名前空間に定義されています。個人的な感想としては,順序を規定しないコレクションである ConcurrentBag クラスが用意されているのが使いやすくて良いと思います。