为什么在tasks
之前执行Task.WhenAll
?
如果您在此处看到,请从下面的代码段开始,首先应打印Console.WriteLine("This should be written first..");
,因为我awaiting
下面的任务是... {/ p>
但是如果您看到输出结果,则会在上述语句之前打印Tasks
方法结果。理想情况下,任务方法应该在我await
时执行,但似乎 - 任务方法在我将它们添加到任务列表中时执行。为什么会这样?
请你告诉我为什么会这样???
代码:
public static async Task Test()
{
var tasks = new List<Task>();
tasks.Add(PrintNumber(1));
tasks.Add(PrintNumber(2));
tasks.Add(PrintNumber(3));
Console.WriteLine("This should be written first..");
// This should be printed last..
await Task.WhenAll(tasks);
}
public static async Task PrintNumber(int number)
{
await Task.FromResult(0);
Console.WriteLine(number);
}
输出
答案 0 :(得分:9)
当您调用async
方法时,您会收到“热门”任务。这意味着在您到达await
之前,任务已经开始运行(甚至可能已完成)。这意味着在调用Task.WhenAll
之前,任务很可能会运行并完成。
但是,在您的情况下,虽然PrintNumber
已标记为async
,但由于您使用的是Task.FromResult
,因此它并非异步。异步方法的同步部分(等待异步任务之前的部分)始终在调用线程上同步执行,并在调用返回之前完成。当您使用Task.FromResult
时,您将获得一个已完成的任务,因此您的所有方法都只是同步部分,并在调用返回之前完成。
答案 1 :(得分:4)
等待完成的任务(由Task.FromResult
创建)时,它会同步完成。这意味着在您的示例中,实际上没有任何异步发生,这解释了执行的顺序。
相反,如果你是
await Task.Yield();
您会看到输出更符合您的期望。
答案 2 :(得分:2)
Task.FromResult
不会导致产量,任务将在同一个线程上执行。要达到你想要的效果,你可以这样做:
public static async Task Test()
{
var tasks = new List<Task>();
tasks.Add(PrintNumber(1));
tasks.Add(PrintNumber(2));
tasks.Add(PrintNumber(3));
Console.WriteLine("This should be written first..");
// This should be printed last..
await Task.WhenAll(tasks);
}
public static async Task PrintNumber(int number)
{
await Task.Yield();
Console.WriteLine(number);
}
答案 3 :(得分:2)
如果您希望Task
或任务在其他内容之后运行,则最容易相应地编写代码。
public static async Task Test()
{
Console.WriteLine("This should be written first..");
// These should be printed last..
await Task.WhenAll(new[]
{
PrintNumber(1),
PrintNumber(2),
PrintNumber(3)
});
}
继续发表评论。
所以我们有一些功能,
async Task<Customer> GetRawCustomer()
{
...
}
async Task<string> GetCity(Customer customer)
{
...
}
async Task<string> GetZipCode(Customer customer)
{
...
}
我们可以像这样使用它们
var rawCustomer = await GetRawCustomer();
var populationWork = new List<Task>();
Task<string> getCity;
if (string.IsNullOrWhiteSpace(rawCustomer.City))
{
getCity = GetCity(rawCustomer);
populationWork.Add(getCity);
}
Task<string> getZipCode;
if (string.IsNullOrWhiteSpace(rawCustomer.City))
{
getZipCode = GetZipCode(rawCustomer);
populationWork.Add(getZipCode);
}
...
await Task.WhenAll(populationWork);
if (getCity != null)
rawCustomer.City = getCity.Result;
if (getZipCode != null)
rawCustomer.ZipCode = getZipCode.Result;