无法理解异步等待行为?

时间:2014-04-03 13:16:39

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

我有以下代码,

using System;
using System.Threading.Tasks;


namespace asyncawait
{
    class Practice
    {
       async Task<int>  Method()
        {
            for (int i = 0; i < int.MaxValue ; i++);

            return 10;
        }

       public async void caller()
        {

           int a = await Method();
           Console.WriteLine("Please print it first");
           Console.WriteLine(a);
           Console.WriteLine("Please print it last");

        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Practice p = new Practice();
            p.caller();
        }
    }
}

构建项目时发出警告

  

Program.cs(9,25,9,31):警告CS1998:这种异步方法缺少“等待”   运营商并将同步运行。考虑使用'await'   运算符等待非阻塞API调用,或'等待Task.Run(...)'   在后台线程上进行CPU绑定工作。

我的期望是,

预期输出:(第一行应立即打印)

  

请先打印//不要等待,因为我没有使用a并且功能正在等待
  10个
  请最后打印

实际输出:

  

请先打印//等待执行功能然后打印输出
  10个
  请最后打印

我不明白,为什么我的函数taking time无法异步工作?在看了很多例子后,我真的无法理解概念。

3 个答案:

答案 0 :(得分:7)

所有async关键字都允许您在函数内使用await关键字。如果您不致电await,则该功能的行为与您根本不执行任何async关键字的行为相同。

从msdn页面看一下这张图片&#34; Asynchronous Programming with Async and Await (C# and Visual Basic)&#34;

enter image description here

如果你按照黑线跟随同一个线程中发生的所有事情,那么在你到达6之前不会中断。然后,此时函数返回并在结果准备好后继续。因为您的代码中没有await您的&#34;黑线&#34;完成整个功能。

为了让它像你想要的那样工作,你需要在函数中发出信号,告诉它应该回到调用者。

   async Task<int>  Method()
    {
        for (int i = 0; i < int.MaxValue ; i++)
        {
            await Task.Yield(); //Your function now returns to the caller at this point then comes back later to finish it. (Your program will be much slower now because it is going to wait int.MaxValue times.)
        }
        return 10;
    }

答案 1 :(得分:1)

当您使用await关键字时,您告诉等待的当前方法,以获取传递给它的Task的结果。魔术来自这样一个事实:在等待时,方法被暂停,调用线程可以继续进行其他工作。

当您将await Method()作为第一个语句时,只有在Method()的结果可用之后才会执行该函数的其余部分,而不管函数之外发生了什么。要实现所需的行为,您应首先触发任务,然后打印第一行,然后等待结果。那就是:

public async void caller() {
    var a = Method();   // <- The task is running now asynchronously
    Console.WriteLine("Please print it first"); // <- The line is printed.
    Console.WriteLine(await a); // <- the result of a is waited for and printed when available.
    Console.WriteLine("Please print it last");
}

另请注意,由于Method关键字,async不会异步执行。要创建异步方法,您应该返回Task,例如:

Task<int> Method() {
    return Task.Run( () => {
        // ... the previous function body...
    });
}

答案 2 :(得分:0)

尝试使用以下代码替换Main()方法的代码:

Task.Run(
() =>
{
      Practice p = new Practice();
      p.caller();
});

你会得到答案。