async 和 await 在哪里结束?困惑

Where does async and await end? Confusion

我有一个程序,它没有任何用途,但可以帮助我了解 async 和 await 的工作原理。这是一个控制台应用程序,它解析 XML 并等待一个名字被 returned,可以是姓氏也可以是名字。这是代码:

static void Main(string[] args)
{
     Task<string> name = GetFirstParsedName();
     name.Wait();
     if (name.IsCompleted)
     {
         Console.WriteLine(name.Result);
     }

     Console.ReadLine();
 }

static async Task<string> GetFirstParsedName()
{
  string xmlSnippet = @"<person>
<FirstName>Chamir</FirstName>
<Surname>Bodasing</Surname>
<Gender>Male</Gender>
<Nationality>South African</Nationality></person>";

  XmlDocument xmlDoc = new XmlDocument();
  xmlDoc.LoadXml(xmlSnippet);

  XmlParser xmlParser = new XmlParser();
  Task<string> t_GetFirstName = xmlParser.GetFirstName(xmlDoc);
  Task<string> t_GetSurname = xmlParser.GetSurname(xmlDoc);  

  Task<string> t_firstReturnedName = await Task.WhenAny(new Task<string>[] { t_GetFirstName, t_GetSurname });

  string firstReturnedName = await t_firstReturnedName;
  return firstReturnedName;    
}

static async Task<string> GetFirstName(XmlDocument personXml)
{
  string firstName = personXml.SelectSingleNode("//FirstName").InnerText;
  await Task.Delay(5000);
  return firstName;
}

static async Task<string> GetSurname(XmlDocument personXml)
{
  string surname = personXml.SelectSingleNode("//Surname").InnerText;
  await Task.Delay(1);
  return surname;
}

似乎只有当您不必 return 将值传递给 main 方法时才使用异步方法才有意义。除非它意味着设置一个全局 class 属性 然后可以访问。如果不是,为了等待该方法,所有方法都需要是异步的,这反过来意味着 return 类型必须是 Task<T>。除非我明确必须编写以下代码(如上面的主要方法),否则它似乎永远不会结束:

Task<string> name = GetFirstParsedName();
name.Wait();
if (name.IsCompleted)
{
    Console.WriteLine(name.Result);
 }

我的理解完全正确吗?我必须使用结果 属性 来获取此处的值,从阅读中可以看出,这似乎不是最佳做法。

It seems like it only makes sense to use the async method when you don't have to return a value to a main method.

为什么这么说?在任何正在进行自然异步操作的地方使用异步方法是有意义的。无论该操作是否具有 return 值。

in order to await the method, all methods need to be async which in turn means that the return type must be "Task" . It seems like it never ends

没错。从 bottom to the top of your stack 开始,Async 在您的代码中像一个 plage 一样传播。它通常到达堆栈中的最高调用位置(无论是控制台 Main 方法还是 UI 事件处理程序)。这就是使用 async 的优势,它允许您在释放调用线程的同时异步等待操作。例如,如果您有一个需要同时处理大量请求的 WebAPI 端点,这会有所帮助。如果您将大部分时间花在查询数据库上,您可以同时释放那个调用线程来处理更多请求。

Is my understanding correct at all? I have to use the result property to get the value here and from reading up about this, it seems that this is not the best practice.

您必须使用 Result 属性 因为控制台应用程序是一种特殊情况,其中 Main 不能标记为 async(除非 ).如果这是一个 UI 事件处理程序或一个 ASP.NET 操作,您应该 await 异步调用。

好吧,async 关键字让编译器知道您的方法将执行一系列异步调用,这些调用最有可能等待但不应阻止 main(或 UI ) 线程。

为了帮助您稍微理解 async-await,这里有一些简单的例子:

考虑这样的场景,当用户在 WinForm 的应用程序上单击 'Save' 按钮时,一些 UI 操作在不同的线程中异步启动。

密码是:

    private Task SomeUIOperation()
    {
        // ui operation
        return Task.Run(() =>
        {
            this.Invoke(new Action(() => this.BackColor = Color.Aquamarine));
            Thread.Sleep(10000);
            this.Invoke(new Action(() => this.BackColor = Color.Gray));
        });
    }

    private async void button1_Click(object sender, EventArgs e)
    {
        await SomeUIOperation();

        // some other stuff
    }

如果我们不在这里使用 async-await UI 线程将无响应 10 秒。

这是一个你通常如何使用async-await的例子,当你希望只有当异步操作完成时才执行一段代码并且同时你不希望主线程被执行时,你可以使用它已屏蔽。

并且控制台应用程序不是测试和学习 Async-Await 的最佳项目类型

It seems like it only makes sense to use the async method when you don't have to return a value to a main method. Unless it means setting a global class property which can then be accessed.

您的 async 方法可以 return Task<T> 到 return 一个值给它的调用者。如果异步方法依赖于副作用(即设置属性/全局变量),它们就不能很好地工作;如果您的代码更纯净(即获取参数和 returning 结果),它们会工作得更好。

If not, in order to await the method, all methods need to be async which in turn means that the return type must be "Task" . It seems like it never ends

这就是为什么 async 的核心原则之一是 "async all the way"。在大多数应用程序中,这正是您应该 做的。最终,"async chain" 通常以 async void 事件处理程序(对于 UI 应用程序)或 async Task<T> 入口点(对于 ASP.NET 应用程序)结束。控制台应用程序很不寻常,因为它们确实需要明确的 Wait()/ResultMain 方法中的等效方法。

毕竟,async 的全部意义在于释放调用线程。如果调用堆栈上层的下一个方法 阻塞 同一个线程,直到 async 代码完成,好吧,这是毫无意义的大量工作...