Code after Task.Delay in delegate not executing

落花浮王杯 提交于 2020-01-05 03:48:51

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!