async和await在哪里结束?混乱
本文关键字:混乱 结束 在哪里 await async | 更新日期: 2023-09-27 18:17:21
我有一个程序,没有目的,但帮助我了解async和await是如何工作的。它是一个控制台应用程序,解析XML并等待返回一个名称,可以是姓,也可以是名。下面是代码:
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;
}
似乎只有在不需要向主方法返回值时才有意义。除非它意味着设置一个全局的类属性,这样就可以被访问。如果不是,为了等待方法,所有方法都需要是异步的,这反过来意味着返回类型必须是Task<T>
。它似乎永远不会结束,除非我显式地编写以下代码(如上面的主方法):
Task<string> name = GetFirstParsedName();
name.Wait();
if (name.IsCompleted)
{
Console.WriteLine(name.Result);
}
我的理解正确吗?我必须使用结果属性来获得这里的值,从阅读关于这一点,似乎这不是最佳实践。
似乎只有在不需要向主方法返回值时才有意义。除非它意味着要设置一个全局的类属性,这样就可以被访问了。
你的async
方法可以返回Task<T>
返回一个值给它的调用者。如果异步方法依赖于副作用(即设置属性/全局变量),它们就不能很好地工作;如果你的代码更纯粹(即接受参数并返回结果),它们会工作得更好。
如果不是,为了等待方法,所有方法都需要是异步的,这反过来意味着返回类型必须是"Task"。似乎永远不会结束
这就是为什么async
的中心原则之一是"异步所有的方式"。在大多数应用程序中,这正是您应该做的。最终,"异步链"通常以async void
事件处理程序(用于UI应用程序)或async Task<T>
入口点(用于ASP)结束。网络应用程序)。主机应用程序是不寻常的,因为它们确实需要显式的Wait()
/Result
或等效的Main
方法。
毕竟,async
的全部意义在于释放调用线程。如果调用堆栈上的下一个方法阻塞了同一个线程,直到async
代码完成,那么,这是一大堆没有任何好处的工作…
似乎只有在不需要向主方法返回值时才有意义。
你为什么这么说?在进行自然异步操作时,使用异步方法是有意义的。不管该操作是否有返回值
为了等待方法,所有方法都需要是异步的,这意味着返回类型必须是"Task"。似乎永远不会结束
这是正确的。Async在你的代码中像一块木板一样,从栈的底部延伸到栈的顶部。它通常到达堆栈中的最高调用位置(无论是控制台Main
方法还是UI事件处理程序)。这就是使用async
的优点,它允许您在释放调用线程的同时异步等待操作。例如,如果您有一个需要并发处理大量请求的WebAPI端点,这将有所帮助。如果你把大部分时间花在查询数据库上,你可以同时释放调用线程来处理更多的请求。
我的理解正确吗?我必须使用结果属性来获得这里的值,从阅读这一点来看,这似乎不是最佳实践。
您必须使用Result
属性,因为控制台应用程序是一种特殊情况,Main
不能被标记为async
(除非您使用ASP。. NET CoreCLR控制台应用程序)。如果这是一个UI事件处理程序或ASP。. NET操作,您将正确地await
异步调用
好吧,async
关键字让编译器知道你的方法将执行一系列异步调用,这些调用应该最有可能等待,但不应该阻塞main
(或UI)线程。
考虑这个场景,当用户在WinForm的应用程序上点击"保存"按钮时,一些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的最佳项目类型