C# 异步和等待在哪里结束?混乱
我有一个程序,它除了帮助我理解async和await是如何工作的外,没有任何目的。它是一个控制台应用程序,解析XML并等待返回一个名字,或者是姓氏,或者是名字。代码如下:C# 异步和等待在哪里结束?混乱,c#,asynchronous,async-await,task-parallel-library,C#,Asynchronous,Async Await,Task Parallel Library,我有一个程序,它除了帮助我理解async和await是如何工作的外,没有任何目的。它是一个控制台应用程序,解析XML并等待返回一个名字,或者是姓氏,或者是名字。代码如下: static void Main(string[] args) { Task<string> name = GetFirstParsedName(); name.Wait(); if (name.IsCompleted) { Console.WriteLin
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;
}
static void Main(字符串[]args)
{
任务名称=GetFirstParsedName();
name.Wait();
如果(name.IsCompleted)
{
Console.WriteLine(name.Result);
}
Console.ReadLine();
}
静态异步任务GetFirstParsedName()
{
字符串xmlSnippet=@”
查米尔
博达斯
男性
南非”;
XmlDocument xmlDoc=新的XmlDocument();
LoadXml(xmlsippet);
XmlParser XmlParser=新的XmlParser();
Task t_GetFirstName=xmlParser.GetFirstName(xmlDoc);
Task t_getnamese=xmlParser.getnamese(xmlDoc);
Task t_firstReturnedName=wait Task.WhenAny(新任务[]{t_GetFirstName,t_getname});
string firstReturnedName=等待t_firstReturnedName;
returnfirstreturnedname;
}
静态异步任务GetFirstName(XmlDocument personXml)
{
字符串firstName=personXml.SelectSingleNode(//firstName”).InnerText;
等待任务。延迟(5000);
返回名字;
}
静态异步任务getNames(XmlDocument personXml)
{
字符串姓氏=personXml.SelectSingleNode(//姓氏”).InnerText;
等待任务。延迟(1);
返回姓氏;
}
似乎只有在不必向主方法返回值的情况下,才有必要使用async方法。除非它意味着设置一个可以访问的全局类属性。如果不是,为了等待该方法,所有方法都需要异步,这意味着返回类型必须是Task
。它似乎永远不会结束,除非我显式地编写以下代码(如上面的主方法所示):
Task name=GetFirstParsedName();
name.Wait();
如果(name.IsCompleted)
{
Console.WriteLine(name.Result);
}
我的理解完全正确吗?我必须使用result属性来获取这里的值,从阅读中,这似乎不是最佳实践
似乎只有在不必向主方法返回值的情况下,才有必要使用async方法
你为什么这么说?在自然进行异步操作的情况下,使用异步方法是有意义的。不管该操作是否有返回值
为了等待该方法,所有方法都需要是异步的,这意味着返回类型必须是“Task”。它似乎永远不会结束
没错。异步像瘟疫一样在代码中传播。它通常到达堆栈中的最高调用位置(无论是控制台Main
方法还是UI事件处理程序)。这就是使用async
的优点,它允许您在释放调用线程的同时异步等待操作。例如,如果您有一个需要同时处理大量请求的WebAPI端点,这可能会有所帮助。如果您将大部分时间花在查询数据库上,您可以同时释放该调用线程以服务更多请求
我的理解完全正确吗?我必须使用result属性来获取这里的值,从阅读中,这似乎不是最佳实践
您必须使用
Result
属性,因为控制台应用程序是一种特殊情况,其中Main
不能标记为async
(除非)。如果这是一个UI事件处理程序或ASP.NET操作,您应该正确地等待
异步调用。好吧,async
关键字让编译器知道您的方法将执行一系列异步调用,这些调用很可能会被等待,但不应该阻止主线程
为了帮助您理解async Wait,下面是一些简单的示例:
考虑这个场景,当用户单击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
}
如果我们不在这里使用异步等待
,UI线程将在10秒内无响应
这是一个通常使用async await的示例,当您希望某段代码仅在异步操作完成时执行,同时又不希望主线程被阻塞时,您可以使用它
控制台应用程序不是测试和学习Async Await的最佳项目类型
似乎只有在不必向主方法返回值的情况下,才有必要使用async方法。除非它意味着设置一个可以访问的全局类属性
您的async
方法可以返回Task
以向其调用者返回值。如果异步方法依赖于副作用(即设置属性/全局),则它们的工作效果不太好;如果您的代码更纯粹(即获取参数并返回结果),它们的工作效果会更好
如果不是,为了等待该方法,所有方法都需要是异步的,这意味着返回类型必须是“Task”。它似乎永远不会结束
这就是为什么async
的核心原则之一是“始终异步”。在大多数应用程序中,这正是您应该做的。最终,“异步链”通常以async void
事件处理程序(对于UI应用程序)或async Task
入口点(对于ASP.NET应用程序)结束。控制台应用程序是不寻常的,因为它们确实需要显式的Wait()
/Result
或其Main
方法中的等效项
毕竟,async
的关键是释放调用线程。如果调用堆栈上的下一个方法阻塞同一个线程,直到async
代码完成,那么,这是一个没有任何好处的大量工作…我相信OP理解async的功能。是控制台造成了混乱。
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
}