C#任务在Task.WhenAll之前执行

时间:2014-12-04 09:35:10

标签: c# .net multithreading task-parallel-library async-await

为什么在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);
}

输出

enter image description here

4 个答案:

答案 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;