简体   繁体   English

这些以下异步方法之间有什么区别?

[英]What is the difference between these following async methods?

I've actually some problems with understanding the principle from async. 在理解异步原理时,我实际上遇到了一些问题。 Can someone tell me the different between the following code examples? 有人可以告诉我以下代码示例之间的区别吗? If someone thinks, that this example are completely wrong can this guy give me a correction? 如果有人认为这个例子是完全错误的,这个家伙可以给我纠正吗?

So here's my code: 所以这是我的代码:

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";
        });
    }

And this: 和这个:

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

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

And why is async != parallel? 为什么异步!=并行? For what should I use async and for what should I use parallel (for example tasks, threads)? 对于什么我应该使用异步,对于什么我应该使用并行(例如任务,线程)?

Parallelism and asynchrony are two different forms of concurrency. 并行和异步是两种不同的并发形式。 Parallelism is using multiple threads (eg, for CPU-bound code). 并行使用多个线程(例如,用于CPU绑定代码)。 Asynchrony uses multiple operations but not necessarily multiple threads (eg, for I/O-bound code). 异步使用多个操作,但不一定使用多个线程(例如,用于I / O绑定代码)。

Task.Run is a kind of bridge between these two worlds. Task.Run是这两个世界之间的桥梁。 It starts (presumably CPU-bound) code running on a background thread, and returns a task that allows the calling thread to treat that work asynchronously. 它启动(可能是受CPU限制)在后台线程上运行的代码,并返回一个任务,该任务允许调用线程异步处理该工作。

While Task.Run is OK for basic parallelism, if you have real CPU-bound work to do, you'd be better off using Parallel or Parallel LINQ. 虽然Task.Run对于基本并行性Task.Run是可以的,但是如果您有真正的CPU约束工作要做,那么最好使用Parallel或Parallel LINQ。

Regarding your code examples, they're both pretty similar: three background tasks are started and the calling thread asynchronously waits for them all to complete. 关于您的代码示例,它们都非常相似:启动了三个后台任务,并且调用线程异步等待它们全部完成。

The first one does call Task<T>.Result , which I discourage, because if there was some exception then Result wraps the exception in an AggregateException while await raises the exception directly. 第一个确实调用了Task<T>.Result ,我不建议这样做,因为如果存在某些异常,则Result将异常包装在AggregateExceptionawait直接引发异常。 The AggregateException complicates error handling. AggregateException使错误处理变得复杂。

The second one calls await individually on each task, which is OK but IMO not ideal. 第二个任务分别await每个任务,虽然可以,但是IMO并不理想。 I think the await Task.WhenAll(..) approach has a clearer intent (and it's just a tiny bit more efficient, too). 我认为await Task.WhenAll(..)方法具有更清晰的意图(而且效率也await Task.WhenAll(..)一点)。

So, I'd recommend combining the approaches: 因此,我建议结合使用以下方法:

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);
}

I also changed the return type to Task . 我还将返回类型更改为Task As a general rule, you should avoid async void , as I describe in an MSDN article. 通常,应避免使用async void ,正如我在MSDN文章中所述。

The implementation of DoHardStuff is a bit questionable, too. DoHardStuff的实现也有问题。 In general, you should use Task.Run to call a method, not as the implementation of a method. 通常,应该使用Task.Run调用方法,而不是作为方法的实现 I have a blog post that goes into details on this subject. 我有一篇博客文章 ,详细介绍了这个主题。

The methods are for reasons of practicality similar. 这些方法出于实用性原因而相似。 However your call to Task.Result is in my opinion where they differ. 但是,我认为您对Task.Result的调用在不同之处。 This assumes the operation is complete and gets the result of the task. 这假定操作已完成并获得任务的结果。 It is pretty dangerous to do this and since it may blow up, you are better off using await . 这样做非常危险,并且由于它可能会炸毁,因此最好使用await

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

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