使用async和await关键字的好处

时间:2015-03-03 20:31:19

标签: c# .net multithreading asynchronous task

我在C#中使用异步方法的新手。我已经读过这些关键字asyncawait有助于通过异步某些方法使程序更具响应性。我有这个片段:

第一种方式

    public static void Main()
    {
        Console.WriteLine("Hello!! welcome to task application");
        Console.ReadKey();
        Task<string> ourtask = Task.Factory.StartNew<string>(() =>
        {
            return "Good Job";
        });
        ourtask.Wait();
        Console.WriteLine(ourtask.Result);
        Console.ReadKey();
    }

第二种方式

 public static void Main()
        {
            Launch();
        }
        public static async void Launch()
        {
            Console.WriteLine("Hello!! welcome to task application");
            Console.ReadKey();
            Console.WriteLine(await GetMessage());
            Console.ReadKey();
        }

        public static Task<string> GetMessage()
        {
            return Task.Factory.StartNew<string>(() =>
                {
                    return "Good Job";
                });
        }

我需要知道:

  1. 两种实现之间是否存在差异(在并行性的概念中)?

  2. 如果我可以创建一个任务并等待它完成,那么使用asyncawait个关键字有什么好处?

5 个答案:

答案 0 :(得分:52)

假设您有一个边界检查点。每辆车都可以一个接一个地通过,让海关看看他们的车,看看他们是不是走私任何比利时巧克力。

现在假设你在你的大众甲壳虫中排成一行,你几乎无法适应,而在你是一辆24轮的monstertruck之前。你现在被困在这个庞然大物的背后很长一段时间,直到海关完成所有搜索之后才能转移给你,他们基本上只需要拍下来告诉你你很高兴。

为了对抗这种效率,我们在边境巡逻队的好朋友有了一个想法并安装了第二个检查站。现在他们可以传递两倍的人数而你可以只拿一个而不是在monstertruck后面等待!

问题解决了吧?不完全是。他们忘了创建通往检查站的第二条道路,因此所有交通都必须通过单车道,导致卡车仍然阻挡甲壳虫。

这与您的代码有何关系?很简单:你也是这样做的。

当你创建一个新的Task时,你基本上创建了第二个检查点。但是,当您现在使用.Wait()同步阻止它时,您就迫使每个人都走这条路。

在第二个示例中,您使用await创建第二条道路,并允许您的车辆与卡车同时处理。

答案 1 :(得分:4)

我会尝试直接回答问题:

  1. 您的两个示例(实际上)都没有涉及任何并行性。我看到它们之间有两个主要区别:1)第一个例子将阻塞一个线程,而任务在第二个线程上运行,这是没有意义的,2)第二个例子将提前退出。遇到await后,控件会立即返回Main(),由于您没有等待Launch()返回的任务完成,您的程序将在此时退出。< / p>

  2. 使用asyncawait与等待任务完成的好处是await在该任务运行时不会阻止当前线程。在引擎盖下,只要编译器遇到await,它就会有效地将该方法的其余部分重写为将在完成任务时调用的回调。这可以释放当前线程在任务运行时执行其他操作,例如响应客户端应用程序中的用户输入或服务Web应用程序中的其他请求。

  3. 坦率地说,这不是展示async / await的好处的好例子。你基本上是说你想做CPU限制工作,而且在完成这项工作之前你不想做任何其他事情。您也可以同步这样做。在进行I / O绑定工作时,Asynchrony真的很闪亮,例如通过网络进行调用(使用正确实现的异步库,如HttpClient),因为你不是简单地将一个线程换成另一个线程,就像在你的第二个例子; there literally is no thread被I / O绑定的工作所消耗。

    正如其他人所提到的,并行性完全是另一个话题。虽然async / await可以帮助您实现它,但有更多参与,而且在我看来,您可以更好地掌握线程释放前的好处。 “继续”走向并行。

    正如其他人所提到的,这是一个很大的话题,我强烈建议你查看一些很棒的资源。由于我已经引用了Stephen Cleary的博客,我将继续给它一个完整的插件 - 他的async/await intro以及随后的帖子都是关于这个主题的优秀入门。

答案 2 :(得分:3)

async / await 清理过多利用 Task.ContinueWith.ContinueWith.ContinueWith 等的复杂代码。

从编码的角度来看,可视化,调试和维护Task.ContinueWith要困难得多,包括必须附带的相关异常处理。

所以,等待出现了,并给了我们这个

    public static void Main()
    {
        Launch();
    }
    public static async void Launch()
    {
        Console.WriteLine("Hello!! welcome to task application");
        Console.ReadKey();
        Console.WriteLine(await GetMessage());
        Console.ReadKey();
    }

    public static Task<string> GetMessage()
    {
        return Task.Factory.StartNew<string>(() =>
            {
                return "Good Job";
            });
    }

这几乎相当于:

    public static void Main()
    {
        Launch();
    }
    public static async void Launch()
    {
        Console.WriteLine("Hello!! welcome to task application");
        Console.ReadKey();
        return  Task.Factory.StartNew(() => GetMessage())
            .ContinueWith((t) => 
                  {
                     Console.WriteLine(t.Result)
                     Console.ReadKey();
                  });
    }

    public static Task<string> GetMessage()
    {
        return Task.Factory.StartNew<string>(() =>
            {
                return "Good Job";
            });
    }

您可以从示例中看到, GetMessage()之后的所有都包含在ContinueWith中,但是该方法会在创建任务后立即返回该任务。所以它返回到调用方法。

这里我们需要等待该任务,否则程序将继续退出:

Launch().Wait();

不必编写ContinueWith()意味着我们的代码变得更具可读性,特别是在我们必须在单个方法中将多个await块链接在一起的情况下,它将“读取”正常。

同样如前所述,更好的异常处理由 await 示例处理,否则我们必须使用TPL方法来处理异常,这也可能使代码库复杂化。

关于你的两个例子,它们并不是真正等效的,所以你不能真正地判断一个。但是, async / await 等同于构造Tasks / ContinueWith。

我认为async / await是TPL演变为实际语言本身。一种语法糖。

答案 3 :(得分:0)

We have two main benefits of async/await programming

1- The nonblocking programming

when you have long-running operations that do not require to block the execution. In this case, you can perform other work while waiting for the result of the long-running task.

Imagine that we have two program flow and they can work in parallel without blocking each other.

Example: Let's say that we need to log every error appear but at the same time this should not block the flow so in that case we can log and return message at the same time.

2- the benefit of thread management in async/await programming

we know that in normal programming (blocking), every line of code is blocking everything after it until it finishes the process even if we have different flows (two flows without any dependency). but in async/await programming, the application will not block this thread, in other words, they will release it to do another work and when the function finishes the work any free thread will handle the response.

C# async and await: Why Do We Need Them?

答案 4 :(得分:0)

border checkpoint analogy一起,我会说:

同步边防员工

您有4条进入的车道和2名警员。处理进来的怪物卡车的警官杰克不知道怪物卡车的确切规则,因此他打电话给办公室。 现在,如果他进行同步,则他会留在电话上等待回复。因此,他无能为力-他的同事玛丽将不得不这样做。

幸运的是,玛丽并行工作,因此她可以同时处理3条畅通的车道。但是,由于她还同步工作,因此一次只能处理一辆车辆。 因此,当她不得不检查侧车上装有猎豹的摩托车的规定时,她必须给总公司打电话,并且还留着电话寻求答案。

现在,我们有两条车道被待处理的工作封锁,而两条车道被封锁,因为没有员工。

异步边防员工

现在,如果杰克工作异步-他将不会排队等待响应。相反,他挂了电话,转到第二车道,处理另一辆车,同时等待总公司回电话。 因为第二泳道是一位非常口吃的女士,所以他要花很多时间。

但是幸运的是,玛丽现在也可以异步工作了,当她完成第二辆车的处理(或者因为必须检查猎豹而将其暂停)后,她可以从怪物卡车办公室接回电话。这样她就可以完成对Monstertruck的处理。
但是,当然,monstertruck在完成后并不会马上消失-驾驶员已经记录了他在检查站度过的时间。幸运的是,玛丽仍然可以并行工作,因此她可以在其他车道上开始处理汽车。

费用

有一天,燃烧人节开始了,许多不寻常的车辆到达边境。这些都给办公室打了很多电话,因此阻塞了所有4条车道。因此,杰克和玛丽只能在车队不断壮大的时候坐在那里等回车。

幸运的是,该地区的土地价格便宜,所以他们的老板决定增加4条车道。虽然这些额外的通道中的一些也被阻塞,以等待办公室的回电,但至少杰克和玛丽一直很忙,不必坐下来等待电话。当然,他们的老板可以考虑雇用一些额外的员工来减少交通拥堵,但是他知道他们将需要住房和培训,而且节日即将结束,所以他就照原样了...

回顾

倾向于ASP.Net:

  • 通道(例如,连接)价格便宜,并且可以轻松扩展(您可能应该增加IIS中的连接限制和队列大小以进行异步操作,例如,请参见下面的“引入参考”)
  • 员工(线程)比较昂贵(例如,请参见下面的“引言参考”)
  • 工作的“慢速”部分(例如I / O或远程http请求),不应阻止昂贵的员工(即应使用async)
  • 注意:工作可能会更改员工(双关语),所以不要与员工保持数据。例如。杰克不应该将Monstertruck-papers放在口袋里,因为Mary可能会对其进行进一步处理-他应该将其退回,或者将其保存在与工作有关的存储中(不要在线程中存储数据,而应该在HttpContext中)< / li>

文学

FWIW:我喜欢technical introduction于2014年发布的 Stephen Cleary