我正在嘗試創建一個異步控制台應用程序,對集合進行一些操作。我有一個版本使用並行for循環,使用異步/等待。我預計異步/等待版本的工作類似於並行版本,但它同步執行。是什么原因呢?
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 var worker = new Worker(); 6 worker.ParallelInit(); 7 var t = worker.Init(); 8 t.Wait(); 9 Console.ReadKey(); 10 } 11 } 12 13 public class Worker 14 { 15 public async Task<bool> Init() 16 { 17 var series = Enumerable.Range(1, 5).ToList(); 18 foreach (var i in series) 19 { 20 Console.WriteLine("Starting Process {0}", i); 21 var result = await DoWorkAsync(i); 22 if (result) 23 { 24 Console.WriteLine("Ending Process {0}", i); 25 } 26 } 27 28 return true; 29 } 30 31 public async Task<bool> DoWorkAsync(int i) 32 { 33 Console.WriteLine("working..{0}", i); 34 await Task.Delay(1000); 35 return true; 36 } 37 38 public bool ParallelInit() 39 { 40 var series = Enumerable.Range(1, 5).ToList(); 41 Parallel.ForEach(series, i => 42 { 43 Console.WriteLine("Starting Process {0}", i); 44 DoWorkAsync(i); 45 Console.WriteLine("Ending Process {0}", i); 46 }); 47 return true; 48 } 49 }
使用await
關鍵字的方式告訴C#,你希望每次通過循環時都等待,而循環並不平行。你可以像這樣重寫你的方法來做你想做的事情,通過存儲Task
s 的列表然后將await
它們全部加入Task.WhenAll
。
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));
代碼: