了解异步方法
本文关键字:异步方法 了解 | 更新日期: 2023-09-27 18:21:27
我有一个方法void getInformation()
,它调用其他5个方法,每个方法都从数据库中获取一些数据。大约需要1秒的时间才能收集到所有数据并返回到getInformation()
,因此我认为我应该在后台收集数据。我的问题是:我可以只将getInformation()
设置为async
,这样在其他方法收集信息时UI就不会被阻止吗?还是必须将其他所有方法都设置为async
?
private void button_Click(object sender, EventArgs e)
{
await getContactInformation();
}
public async Task getContactInformation()
{
this.data.Add(collectData1());
this.data.Add(collectData2());
this.data.Add(collectData3());
this.data.Add(collectData4());
this.data.Add(collectData5());
}
首先,async
的理想情况是使用"async all way"。在这种情况下,您的代码将如下所示:
private async void button_Click(object sender, EventArgs e)
{
await getContactInformationAsync();
}
public async Task getContactInformationAsync()
{
this.data.Add(await collectData1Async());
this.data.Add(await collectData2Async());
this.data.Add(await collectData3Async());
this.data.Add(await collectData4Async());
this.data.Add(await collectData5Async());
}
请注意,现代数据库API,如EntityFramework6、ADO.NET、SQLite等,都有异步API,可以用来实现collectDataNAsync
方法。这是理想的async
场景,因为它最大限度地减少了线程浪费,并使UI保持良好的响应性。
然而,如果您想要更多的"快速修复",那么您可以将(同步)调用推送到后台线程,然后异步处理后台工作,例如:
private async void button_Click(object sender, EventArgs e)
{
await Task.Run(() => getContactInformation());
}
public void getContactInformation()
{
this.data.Add(collectData1());
this.data.Add(collectData2());
this.data.Add(collectData3());
this.data.Add(collectData4());
this.data.Add(collectData5());
}
这将以牺牲线程池线程为代价来解决眼前的问题(释放UI线程)。这不是理想的,但它会起作用。
通常,我建议将所有IO从UI线程中删除,但对每个单独的调用async
没有意义。
对于async
调用对数据库IO阻塞线程的影响的指导,我发现了这个非常清晰和有用的建议。
http://blogs.msdn.com/b/rickandy/archive/2009/11/14/should-my-database-calls-be-asynchronous.aspx
否。您的方法体必须使用等待,否则将收到警告。
很简单。
用…包裹你的方法体。。。
await Task.Run(()=>{
// do your thing
});
我可以让getInformation()异步,这样在其他方法收集信息时UI就不会被阻塞吗?还是必须让其他所有方法异步?
后者。当您执行async
时,它是"async all way",这意味着您将async
方法调用一直进行到堆栈的顶部。对于IO绑定操作,不需要使用后台线程,因为现在大多数API都公开了真正异步的XXXAsync
方法调用,这意味着在执行IO请求时,UI消息循环可以自由处理其他消息。
不过,需要注意的一点是,标记方法async
不足以使其异步。实际上,您必须await
一个异步操作,例如数据库方法调用。如果没有对数据库的异步API调用,您将无法进行异步。
在您的情况下,getContactInformation
将使编译器省略一个警告,说明您有一个未等待的异步方法。事实上,如果你await getInformation()
,你将完全同步运行。