C# 使用await async的最佳实践,从何处开始任务?
我开始在.NETWPF应用程序中使用wait/async机制 在我的ViewModel中,我正在调用一个服务的异步方法 我的问题是: 这样更好吗C# 使用await async的最佳实践,从何处开始任务?,c#,.net,wpf,asynchronous,C#,.net,Wpf,Asynchronous,我开始在.NETWPF应用程序中使用wait/async机制 在我的ViewModel中,我正在调用一个服务的异步方法 我的问题是: 这样更好吗 直接在这个服务内部,做一个大的返回等待任务 使此服务上的所有子方法都是异步的,然后在此子方法中有任务。运行 举例来说: (一) 公共类服务:iSeries{ 公共异步任务(SomeParameter){ 返回等待任务。运行(()=>{ CopyStuff(参数A); 升级材料(参数B); 返回重载(parameter.C) }); } 私有void C
返回等待任务代码>
任务。运行
公共类服务:iSeries{
公共异步任务(SomeParameter){
返回等待任务。运行(()=>{
CopyStuff(参数A);
升级材料(参数B);
返回重载(parameter.C)
});
}
私有void CopyStuff(ParamA参数){
…//某些长操作将主要在磁盘上等待
}
私有void UpgradeStuff(ParamB参数){
…//一些不应该阻塞GUI线程的长操作
}
public SomeResult重载(ParamC参数){
return…;//重新启动某些服务并返回其成功的长操作
}
}
(二)
公共类服务:iSeries{
公共异步任务(SomeParameter){
等待CopyStuff(参数A);
等待升级(参数B);
返回等待重新加载(parameter.C)
}
专用异步任务CopyStuff(ParamA参数){
return wait Task.Run(()=>{…});//一些主要在磁盘上等待的长操作
}
专用异步任务UpgradeStuff(ParamB参数){
return wait Task.Run(()=>{…});//一些不应该阻塞GUI线程的长操作
}
公共异步任务重载(ParamC参数){
return wait Task.Run(()=>{return…});//重新启动某些服务并返回其成功的长操作
}
}
我可以看出这两种方法的优点:
- 在1)我们将使用更少的任务,这可能是最有效的(?)
- 在2)中,这感觉与async Wait方法更“兼容”,这将允许更改某些方法的可见性,并且仍然是异步的,这将允许这些方法在某一天需要时并行运行
您的服务只是将工作推送到另一个
ThreadPool
线程,该线程将在方法执行期间被阻止。而在客户端,这听起来并不坏,在服务器端使用这一原则确实会损害您的可伸缩性 斯蒂芬·克利里说: 不使用Task.Run中的实现方法;相反,使用 运行以调用该方法 如果服务方法是真正同步的,则不应使用假异步签名包装它们;如果不想在重载方法执行时阻止UI线程,则应使用Task.Run从视图模型调用服务方法。
我建议你阅读斯蒂芬·克利里(Stephen Cleary)在其博客中的系列文章。
考虑对I/O操作使用异步方法 <> P>此外,我可以看到,您的服务所做的工作不仅仅是CPU绑定的工作,如果是这样,您应该考虑使用内置I/O异步API方法,如果在现在使用的同步(例如)上可用的话,在这种情况下,您的方法将是一个真正的异步方法,而不是像现在一样的假异步包装器。
如果您愿意这样做,在执行I/O异步操作时,您的UI线程将不会阻塞,但如果仍然涉及大量CPU绑定的工作,并且您不想在CPU绑定的工作执行期间阻塞UI,则仍然可以使用Task。在从视图模型调用服务方法时运行(即使方法签名已经是异步签名)。
在上面的系列文章中,我们将详细介绍同步和异步方法的混合 在异步API方法中使用bult的另一个巨大优势是,如果该方法是真正异步的,则在执行异步I/O操作时,您可以使用任何
ThreadPool
线程,而更多ThreadPool
线程可以自由执行任何其他工作。在服务器端使用异步编程时,这一点尤其重要(但不仅如此),它可以真正提高您的可伸缩性。
异步和MVVM
最后一件事,如果您遵循MVVM模式,那么您可以使用一个很好的阅读材料。在您的情况下,您需要使用
Task.Run
使UI响应,对吗?我建议服务类是一个普通的同步类,并且您调用Task.Run
一次,尽可能靠近UI。例如,在我们的MVVM命令处理程序。就我的两分钱:在第二种方法中,如果您不关心同步上下文,请不要忘记在每个wait
调用上使用configurewait(false)
。这会给您带来一点性能提升(特别是当许多wait
s将被顺序调用时)因为运行时不会每次切换上下文。@YacoubMassad是的,但这意味着每次使用此服务时,我都必须声明一个新任务,并且它们永远无法与其他任务并行运行,不是吗?什么“永远无法并行运行”?服务中的单个操作?返回等待任务。运行(…)
与返回任务相同。使用一些不必要的开销运行(…)
。并不是async
或wait
使某个任务异步运行。它们基本上是为了让等待某个任务更容易完成,除非在某个时间有一个方法
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
}
}
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
}
}