以下异步方法有什么区别?

时间:2014-12-19 14:50:12

标签: c# asynchronous parallel-processing async-await task

我从异步中了解原理实际上存在一些问题。有人能告诉我下面的代码示例之间的区别吗?如果有人认为,这个例子完全错了,这家伙可以给我一个更正吗?

所以这是我的代码:

private async void DoHardStuffAsync()
    {
        var result = DoHardStuff();
        var secondResult = DoHardStuff();
        var thirdResult =  DoHardStuff();

        await Task.WhenAll(result, secondResult, thirdResult);

        MessageBox.Show(result.Result + secondResult.Result + thirdResult.Result);
    }

    private Task<string> DoHardStuff()
    {
        return Task.Run(() =>
        {
            var time = DateTime.Now;
            while (DateTime.Now.Subtract(time).Milliseconds < 900)
            { }

            return "finished";
        });
    }

而且:

private async void DoHardStuffAsync()
    {
        var result = DoHardStuff();
        var secondResult = DoHardStuff();
        var thirdResult =  DoHardStuff();

        MessageBox.Show(await result + await secondResult + await thirdResult);
    }

为什么异步!=并行?我应该使用什么异步以及我应该使用并行(例如任务,线程)?

2 个答案:

答案 0 :(得分:3)

Parallelism和asynchrony是两种不同的并发形式。并行性使用多个线程(例如,用于CPU绑定的代码)。异步使用多个操作,但不一定是多个线程(例如,对于I / O绑定的代码)。

Task.Run是这两个世界之间的桥梁。它启动(可能是CPU绑定的)代码在后台线程上运行,并返回一个允许调用线程异步处理该工作的任务。

虽然Task.Run对于基本并行性是可行的,但如果你有真正的CPU限制工作要做,那么最好使用Parallel或并行LINQ。

关于你的代码示例,它们都非常相似:启动了三个后台任务,并且调用线程异步等待它们全部完成。

第一个调用Task<T>.Result,我不鼓励,因为如果有异常,Result将异常包装在AggregateException中,而await直接引发异常。 AggregateException使错误处理变得复杂。

第二个人在每个任务上单独调用await,这是可以的,但IMO并不理想。我认为await Task.WhenAll(..)方法具有更清晰的意图(而且它的效率也更高一些)。

所以,我建议结合这些方法:

private async Task DoHardStuffAsync()
{
  var result = DoHardStuff();
  var secondResult = DoHardStuff();
  var thirdResult =  DoHardStuff();

  await Task.WhenAll(result, secondResult, thirdResult);

  MessageBox.Show(await result + await secondResult + await thirdResult);
}

我还将返回类型更改为Task。作为一般规则,您应avoid async void,正如我在MSDN文章中所描述的那样。

DoHardStuff的实施也有点可疑。通常,您应该使用Task.Run 调用方法,而不是方法的实现。我有一个blog post详细介绍了这个主题。

答案 1 :(得分:0)

这些方法的实用性类似。但是,您对 Task.Result 的调用在我看来不同。这假设操作已完成并获得任务结果。这样做是非常危险的,因为它可能会爆炸,你最好使用 await