コレクションで何らかの作業を行う非同期コンソールアプリを作成しようとしています。非同期forループを使用する1つのバージョンと、async/awaitを使用する別のバージョンがあります。 async/awaitバージョンはパラレルバージョンと同様に動作するはずですが、同期的に実行されます。私は何を間違えていますか?
class Program
{
static void Main(string[] args)
{
var worker = new Worker();
worker.ParallelInit();
var t = worker.Init();
t.Wait();
Console.ReadKey();
}
}
public class Worker
{
public async Task<bool> Init()
{
var series = Enumerable.Range(1, 5).ToList();
foreach (var i in series)
{
Console.WriteLine("Starting Process {0}", i);
var result = await DoWorkAsync(i);
if (result)
{
Console.WriteLine("Ending Process {0}", i);
}
}
return true;
}
public async Task<bool> DoWorkAsync(int i)
{
Console.WriteLine("working..{0}", i);
await Task.Delay(1000);
return true;
}
public bool ParallelInit()
{
var series = Enumerable.Range(1, 5).ToList();
Parallel.ForEach(series, i =>
{
Console.WriteLine("Starting Process {0}", i);
DoWorkAsync(i);
Console.WriteLine("Ending Process {0}", i);
});
return true;
}
}
await
キーワードの使用方法は、ループを通過するたびに待機することをC#に伝えますが、これは並行ではありません。 Task
sのリストを保存してから Task.WhenAll
ですべてをawait
ingすることで、このようにメソッドを書き換えて、目的の処理を実行できます。
public async Task<bool> Init()
{
var series = Enumerable.Range(1, 5).ToList();
var tasks = new List<Task<Tuple<int, bool>>>();
foreach (var i in series)
{
Console.WriteLine("Starting Process {0}", i);
tasks.Add(DoWorkAsync(i));
}
foreach (var task in await Task.WhenAll(tasks))
{
if (task.Item2)
{
Console.WriteLine("Ending Process {0}", task.Item1);
}
}
return true;
}
public async Task<Tuple<int, bool>> DoWorkAsync(int i)
{
Console.WriteLine("working..{0}", i);
await Task.Delay(1000);
return Tuple.Create(i, true);
}
コードは、各操作(await
を使用)が完了するのを待ってから、次の反復を開始します。
したがって、並列性は得られません。
既存の非同期操作を並行して実行する場合、await
は不要です。 Task
sのコレクションを取得し、Task.WhenAll()
を呼び出して、それらすべてを待機するタスクを返す必要があります。
return Task.WhenAll(list.Select(DoWorkAsync));
public async Task<bool> Init()
{
var series = Enumerable.Range(1, 5);
Task.WhenAll(series.Select(i => DoWorkAsync(i)));
return true;
}