如何在循环中使用await?

我正在尝试创建一个异步控制台应用程序,对集合进行一些操作。我有一个版本使用并行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#,你希望每次通过循环时都等待,而循环并不平行。你可以像这样重写你的方法来做你想做的事情,通过存储Tasks 的列表然后将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; 你只需要得到一个Tasks 的集合并且调用Task.WhenAll()返回一个等待它们的任务:

return Task.WhenAll(list.Select(DoWorkAsync));

 代码:

https://github.com/kuaidaoyanglang/TaskTest

posted @ 2018-09-07 01:20  杨浪  阅读(4639)  评论(0编辑  收藏  举报