For*_*ibs 1 c# asynchronous async-await
我正在尝试同时处理列表的分区。对于列表中每个分区中的每个整数,我正在尝试等待该时间。
public class Program
{
public async static void Main()
{
Console.WriteLine("Starting.");
var values = Enumerable.Range(0,1000).ToList();
await Task.WhenAll(
from partition in Partitioner.Create(values).GetPartitions(10)
select Task.Run(async delegate {
Console.WriteLine("Entered");
using (partition)
while (partition.MoveNext()){
var delay = partition.Current;
await Task.Delay(delay);
Console.WriteLine(string.Format("Waited {0} milliseconds",delay));
}
}));
Console.WriteLine("Done");
}
}
Run Code Online (Sandbox Code Playgroud)
在Task.Delay(delay)之后执行似乎停止:
Starting.
Entered
Entered
Waited 0 milliseconds
Entered
Entered
Entered
Entered
Entered
Entered
Entered
Entered
Run Code Online (Sandbox Code Playgroud)
简短答案
更改Main定义以返回Task:
public async static Task Main()
Run Code Online (Sandbox Code Playgroud)
更长的答案
异步方法实际上首先是同步运行的,直到第一个await。如果Task通过您调用的任何方法(Task.WhenAll在这种情况下)返回的that 还没有完成,则该await关键字通过将a返回Task到调用方法,并将该方法的其余部分作为续接上的方法,使事情变得异步Task。
因此,这意味着您的Main方法实际上在Task.Delay()命中第一个之后就返回了Task,因为返回a 触发Task.Run了返回a Task,触发Task.WhenAll()了返回a Task。由于您的Main方法返回void,因此.NET不知道任何内容仍在运行,并且程序结束了。
如果返回a Task,则.NET将等待直到Task完成。
如果需要,可以在此处阅读有关有效Main签名的更多信息。
请注意,async方法签名仅在C#7.1+中有效。如果您不能使用C#7.1+,则可以async从Main方法中删除并使用Task.WaitAll()代替await Task.WhenAll()(但您还必须调用.ToArray()该集合,因为WaitAll()它没有IEnumerable<Task>像接受那样的重载WhenAll())。这将阻塞主线程,但是在控制台应用程序中这并不是什么大问题。