使用wait-async的最佳实践,在哪里启动任务
本文关键字:在哪里 启动 任务 wait-async 最佳 使用 | 更新日期: 2023-09-27 18:13:25
我开始在。net WPF应用程序中使用await/async机制。
在我的ViewModel中,我调用了一个服务上的异步方法。
我的问题是:是否
- 直接在这个服务内部,创建一个大的
return await Task.Run(()=>{...});
- 这个服务上的所有子方法也是异步的,然后里面有
Task.Run
吗?
1)
public class Service:IService{
public async Task<SomeResult>(SomeParameter parameter){
return await Task.Run(()=>{
CopyStuff(parameter.A);
UpgradeStuff(parameter.B);
return ReloadStuff(parameter.C)
});
}
private void CopyStuff(ParamA parameter){
...//Some long operation that will mainly wait on the disk
}
private void UpgradeStuff(ParamB parameter){
...//Some long operation that should not block the GUI thread
}
public SomeResult ReloadStuff(ParamC parameter){
return ...;//Some long operation that relaunch some services and return their successs
}
}
2)
public class Service:IService{
public async Task<SomeResult>(SomeParameter parameter){
await CopyStuff(parameter.A);
await UpgradeStuff(parameter.B);
return await ReloadStuff(parameter.C)
}
private async Task CopyStuff(ParamA parameter){
return await Task.Run(()=>{...});//Some long operation that will mainly wait on the disk
}
private async Task UpgradeStuff(ParamB parameter){
return await Task.Run(()=>{...});//Some long operation that should not block the GUI thread
}
public async Task<SomeResult> ReloadStuff(ParamC parameter){
return await Task.Run(()=>{return ...});//Some long operation that relaunch some services and return their successs
}
}
我可以看到两种方法的优点:
- 1)我们将使用更少的任务,这可能是最有效的(???)
- 在2)这感觉更符合async-await方法,这将允许改变一些方法的可见性,仍然是异步的,这将允许方法并行运行,如果需要的一天。
选择哪个选项?
我不会使用你的两个选项,它们都会创建一个误导性的API,每个使用你的服务的人都会认为他使用异步方法,但事实是在错误签名的背后,这些方法实际上根本不是异步的。
你的服务只是将工作推送到另一个ThreadPool
线程,该线程将在方法执行期间被阻塞。
虽然在客户端听起来并没有那么糟糕,但在服务器端使用这个原则确实会损害您的可伸缩性。
根据Stephen Cleary:
如果你的服务方法真的是同步的,你不应该用假的异步签名来包装你的服务方法,如果你不想在heavy方法执行的时候阻塞UI线程,你应该使用Task。当您从视图模型调用服务方法时运行。不使用任务。运行中实现的方法;相反,使用的任务。
我建议你读读Stephen Cleary的《任务》系列。在他的博客上运行礼仪文章
考虑使用异步方法进行I/O操作
此外,我可以看到你的服务所做的工作不仅仅是CPU绑定的工作,如果是这样,你应该考虑使用内置的I/O异步API方法,如果有任何可用的同步你现在使用(例如异步文件I/O),在这种情况下,你的方法将是一个真正的异步方法,而不是一个假的异步包装,因为他们现在。
如果你这样做,你的UI线程将不会阻塞,而I/O异步操作将执行,但如果仍然有繁重的CPU绑定工作涉及,你不想在CPU绑定工作执行期间阻塞UI,你仍然可以使用Task。当你从视图模型调用服务方法时运行(即使方法签名已经是异步的)。
关于同步和异步方法混合的更多信息,请参阅上述系列文章。
使用内置异步API方法的另一个巨大优势是,如果该方法是真正异步的,则在执行异步I/O操作时不会阻塞任何ThreadPool
线程,并且更多的ThreadPool
线程可以自由地做任何其他工作。
在服务器端使用异步编程时,这一点尤其重要(但不仅如此),它可以真正提高您的可伸缩性。
Async and MVVM
最后一件事,如果你遵循MVVM模式MSDN"异步MVVM"的文章是一个很好的阅读材料,你可以使用