C# 如何在循环中使用 await
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19431494/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use await in a loop
提问by Satish
I'm trying to create an asynchronous console app that does a some work on a collection. I have one version which uses parallel for loop another version that uses async/await. I expected the async/await version to work similar to parallel version but it executes synchronously. What am I doing wrong?
我正在尝试创建一个异步控制台应用程序,它对集合进行一些工作。我有一个使用并行 for 循环的版本,另一个使用 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;
}
}
采纳答案by Tim S.
The way you're using the await
keyword tells C# that you want to wait each time you pass through the loop, which isn't parallel. You can rewrite your method like this to do what you want, by storing a list of Task
s and then await
ing them all with Task.WhenAll
.
您使用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);
}
回答by SLaks
Your code waits for each operation (using await
) to finish before starting the next iteration.
Therefore, you don't get any parallelism.
await
在开始下一次迭代之前,您的代码会等待每个操作(使用)完成。
因此,您不会获得任何并行性。
If you want to run an existing asynchronous operation in parallel, you don't need await
; you just need to get a collection of Task
s and call Task.WhenAll()
to return a task that waits for all of them:
如果要并行运行现有的异步操作,则不需要await
; 您只需要获取Task
s的集合并调用Task.WhenAll()
返回等待所有这些的任务:
return Task.WhenAll(list.Select(DoWorkAsync));
回答by Vladimir
public async Task<bool> Init()
{
var series = Enumerable.Range(1, 5);
Task.WhenAll(series.Select(i => DoWorkAsync(i)));
return true;
}
回答by Mehdi Dehghani
In C# 7.0 you can use semantic names to each of the members of the tuple, here is Tim S.'s answer using the new syntax:
在 C# 7.0 中,您可以对 tuple 的每个成员使用语义名称,这是Tim S.使用新语法的答案:
public async Task<bool> Init()
{
var series = Enumerable.Range(1, 5).ToList();
var tasks = new List<Task<(int Index, bool IsDone)>>();
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.IsDone)
{
Console.WriteLine("Ending Process {0}", task.Index);
}
}
return true;
}
public async Task<(int Index, bool IsDone)> DoWorkAsync(int i)
{
Console.WriteLine("working..{0}", i);
await Task.Delay(1000);
return (i, true);
}
You could also get rid of task.
inside foreach
:
你也可以摆脱task.
insideforeach
:
// ...
foreach (var (IsDone, Index) in await Task.WhenAll(tasks))
{
if (IsDone)
{
Console.WriteLine("Ending Process {0}", Index);
}
}
// ...