问题
I am trying to concurrently process partitions of a list. For each integer in each partition of the list I am trying to wait for that amount of time.
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");
}
}
Execution appears to stop after Task.Delay(delay):
Starting.
Entered
Entered
Waited 0 milliseconds
Entered
Entered
Entered
Entered
Entered
Entered
Entered
Entered
回答1:
Short answer
Change your Main
definition to return a Task
:
public async static Task Main()
Longer answer
Asynchronous methods actually run synchronously at first, up until the first await
. If the Task
that is returned by whatever method you called (Task.WhenAll
in this case) has not completed yet, then the await
keyword makes things asynchronous by returning a Task
to the calling method, and signing up the rest of the method as a continuation on that Task
.
So that means that your Main
method actually returns after the first Task.Delay()
is hit, beacuse that returns a Task
, which triggers Task.Run
to return a Task
, which triggers Task.WhenAll()
to return a Task
. Since your Main
method returns void
, then .NET has no idea anything is still running and your program ends.
If you return a Task
, then .NET will wait until that Task
is completed.
If you want, there is extra reading here about the valid Main
signatures.
Note that the async
method signatures only work in C# 7.1+. If you can't use C# 7.1+, then you can remove async
from the Main
method and use Task.WaitAll() instead of await Task.WhenAll()
(but you also have to call .ToArray()
on the collection, since WaitAll()
doesn't have an overload that accepts IEnumerable<Task>
like WhenAll()
does). That will block the main thread, but it's not really a big deal in a console app.
来源:https://stackoverflow.com/questions/57894077/code-after-task-delay-in-delegate-not-executing