繁体   English   中英

如何等待异步任务

[英]How to wait on Async tasks

static void Main(string[] args)
{
    Action myAction = async () =>
    {
        await Task.Delay(5);
        Console.WriteLine(Interlocked.Add(ref ExecutionCounter, 1));                
    };

    var actions = new[] { myAction, myAction, myAction };

    Task.WaitAll(actions.Select(a => Execute(a)).ToArray());  //This blocks, right?

    Console.WriteLine("Done waiting on tasks.");
    Console.ReadLine();
}

static int ExecutionCounter = 0;

private static Task Execute(Action a)
{
    return Task.Factory.StartNew(async () =>
    {
        await Task.Delay(5);
        a();
    });
}

这看起来很简单,但是自然地,输出总是看起来像这样(数字的顺序当然会改变):

等待任务完成。

2

1个

3

我在这里想念什么? 为什么Task.WaitAll不会像我期望的Task.WaitAll阻塞?

因此,这里有几个单独的错误。

首先,对于Execute ,您将StartNewasync lambda一起使用。 由于StartNew没有像Task.Run这样的Task<Task>返回过载, Task.Run您有一个返回Task的方法,该方法指示异步操作何时完成启动 ,而不是异步操作何时完成,这意味着Execute返回的Task将立即完成,而不是在Delay完成或您调用的操作完成之后。 此外,运行异步方法时根本没有理由完全使用StartNewRun ,您可以正常执行它们并await它们,而无需将它们推送到线程池线程中。

接下来, Execute接受一个Action ,这意味着它是一个同步方法,不计算任何值。 您提供的是一个异步方法,但是由于委托没有返回Task ,因此Execute无法await它。 如果希望Execute处理异步方法,则需要接受返回Task的委托。

因此,鉴于所有Execute应该看起来像这样。

private static async Task Execute(Func<Task> action)
{
    await Task.Delay(TimeSpan.FromMilliseconds(5));
    await action();
}

接下来进入Main方法。 如前所述,当您尝试提供async方法时, Execute接受Action 这意味着在运行操作时,代码将在您的操作完成之前继续执行。 您需要将其调整为使用Task返回方法。

所有一切后,你的代码仍然有它的竞争条件,在概念层面,这将阻止你获得理论上的结果以正确的顺序。 您正在并行执行3个不同的操作,因此,它们可以按任何顺序完成。 在原子地递增计数器的同时,有可能一个线程输出一个计数器,然后运行另一个线程,递增计数器,打印其值,然后让另一个线程再次运行并打印出该值,这可能是因为您所拥有的,即使修复了上述所有错误之后也是如此。 为了确保按顺序打印值,您需要确保增量和控制台写入是原子执行的

现在,您可以像这样写出Main方法:

int ExecutionCounter = 0;
object key = new object();
Func<Task> myAction = async () =>
{
    await Task.Delay(TimeSpan.FromMilliseconds(5));
    lock (key)
    {
        Console.WriteLine(++ExecutionCounter);
    }
};

var actions = new[] { myAction, myAction, myAction };

Task.WaitAll(actions.Select(a => Execute(a)).ToArray());  //This blocks, right?

是的,正如您的评论所提到的,调用WaitAll将阻止,而不是异步。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM