【问题标题】:Why is invoking a method on the same line as awaiting it considered asynchronous?为什么调用与等待它在同一行上的方法被认为是异步的?
【发布时间】:2016-09-11 18:06:02
【问题描述】:

我正在查看 http://www.dotnetperls.com/async 上的示例以更好地理解 async/await,但以下内容让我感到困惑:

我理解为什么下面的示例被认为是异步的。 HandleFileAsync 被调用,Console.WriteLine 调用被调用,然后我们等待 task 完成后再继续。

static async void ProcessDataAsync()
{
     // Start the HandleFile method.
     Task<int> task = HandleFileAsync("C:\\enable1.txt");

     // Control returns here before HandleFileAsync returns.
     // ... Prompt the user.
     Console.WriteLine("Please wait patiently " +
         "while I do something important.");

     // Wait for the HandleFile task to complete.
     // ... Display its results.
     int x = await task;
     Console.WriteLine("Count: " + x);
}

然而在下面的例子中,我们等待调用 Task.Run 来运行一个动作:

static async void Example()
{
     // This method runs asynchronously.
     int t = await Task.Run(() => Allocate());
     Console.WriteLine("Compute: " + t);
}

那么,如果我们在这里等待 Task.Run 的完成,异步到底发生了什么?我认为一旦我们等待后续任务的执行完成,它就会变成一次阻塞调用,在这种情况下,它是在同一行上调用的。

我错过了什么?

【问题讨论】:

  • HandleFileAsync 直到你最后 await 它才会被调用,所以你的 sn-ps 在异步功能方面基本相同。您只是将指针指向顶部的任务。但是,我相信您误解了 async 的作用。它只是在不阻塞主上下文线程(或 GUI 应用程序的 UI 线程)方面是异步的。代码仍将按顺序逐行运行 - HandleFileAsync 不会与 ProcessDataAsync 中的其余代码并行运行。
  • @Rob:一点也不。在ProcessDataAsync 的第一行调用HandleFileAsync
  • @bulletblue:我同意 Eric Lippert 的观点,即 dotnetperls 教程令人困惑且有些误导。我有 an async intro of my own 可以帮助你。
  • @StephenCleary 如果Task&lt;int&gt; task = HandleFileAsync(...) 行运行但从未等待任务,预期的行为是什么? HandleFileAsync 是否已执行,但我们只是没有得到结果?那么如果我们不关心结果而只关心执行,我们可以选择不等待吗?
  • @Howiecamp:大多数时候“一劳永逸”是一个错误。你确定你不在乎结果吗?你不需要知道它是否失败? (异常将被放置在您的代码将忽略的任务上)。您不需要知道它何时完成,因此您的代码知道退出程序是安全的?

标签: c# async-await


【解决方案1】:

异步到底发生了什么?
考虑一下:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication2
{
    class Program
    {
        static volatile uint i;
        static uint Test()
        {
            Thread.Sleep(1000);
            i = 2; //uint.MaxValue;
            while (i-- > 0) { }
            return i;
        }

        static bool done;
        static async void Example()
        {
            var t = await Task.Run(() => Test());
            Console.WriteLine("result: " + t);
            done = true;
        }
        static void Main(string[] args)
        {
            Example();
            Console.WriteLine("wait: Control returns here before Example() returns ");
            while (!done) { }
            Console.WriteLine("done ");
        }
    }
}

Example(); 本身是异步发生的。 所以如果你删除while (!done) { }
程序在Example() 完成之前退出。
我希望这会有所帮助。

【讨论】:

    【解决方案2】:

    我认为一旦我们等待后续任务的执行完成,它就会变成一次阻塞调用,在这种情况下,它是在同一行调用的。我错过了什么?

    你的信念是错误的;这就是你所缺少的。 “await”的意思是“现在返回,在我们异步等待的时候去运行别的东西,当结果可用时,回到这里。”

    获取任务的结果就像你认为 await 所做的那样。如果它所做的只是同步获取任务的结果,我们就不必发明 await 了!它异步获取任务的结果。

    虽然我们正在这样做,但此评论是错误的:

    // Control returns here before HandleFileAsync returns.
    

    这怎么可能? HandleFileAsync 返回了一个任务!如果 HandleFileAsync 没有返回,控制是如何到达手头有一个任务的?当然它回来了。

    而且这条评论具有误导性:

    // Wait for the HandleFile task to complete.
    

    这应该是异步等待任务完成。异步等待,记住,我们的意思是“现在返回,去运行更多的工作,当任务完成时,在手头有结果的情况下继续这一点。”

    如果我是你,我会找到更好的教程。

    【讨论】:

      猜你喜欢
      • 2016-12-31
      • 2023-01-26
      • 1970-01-01
      • 1970-01-01
      • 2016-02-24
      • 2019-06-05
      • 2015-11-09
      • 2019-10-11
      • 1970-01-01
      相关资源
      最近更新 更多