wpf 使用 await-async 的最佳实践,从哪里开始任务?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/40104279/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Best practices to use await-async, where to start the task?
提问by J4N
I started to use the await/async mechanism in our .Net WPF application.
我开始在我们的 .Net WPF 应用程序中使用 await/async 机制。
In my ViewModel, I'm calling an async method on a service.
在我的 ViewModel 中,我正在调用服务上的异步方法。
My question is: Is it better to
我的问题是:最好
- Directly inside this service, make one big
return await Task.Run(()=>{...}); - Have all the submethods on this service being also async and then inside this have the
Task.Run?
- 直接在这个服务里面,做一个大的
return await Task.Run(()=>{...}); - 此服务上的所有子方法是否也是异步的,然后在其中包含
Task.Run?
By example:
举例:
1)
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)
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
}
}
I can see advantages in both approaches:
我可以看到两种方法的优点:
- In 1) we will use less task, this is probably most efficient(???)
- In 2) This feel more "compliant" with the async-await approach, this would allow to change the visibility of some methods and still being async, this would allow the methods to run in parallel if required one day.
- 1)我们将使用更少的任务,这可能是最有效的(???)
- 在 2) 这感觉更“符合”异步等待方法,这将允许更改某些方法的可见性并且仍然是异步的,这将允许这些方法在有一天需要时并行运行。
采纳答案by YuvShap
Which option to choose?
选择哪个选项?
I would use neither of your options, both of them will create an misleading API, everyone that will use your service will think that he uses async methods but the truth is that behind the false signature the methods are actually not asynchronous at all.
Your service just pushes the work to another ThreadPoolthread that will be blocked during the method execution.
While in the client side that does not sound that bad in server side using this principle can really hurt your scalability.
我不会使用您的任何选项,它们都会创建一个误导性的 API,使用您的服务的每个人都会认为他使用异步方法,但事实是,在虚假签名背后,这些方法实际上根本不是异步的。
您的服务只是将工作推送到ThreadPool将在方法执行期间被阻塞的另一个线程。
而在客户端,使用这个原则在服务器端听起来并没有那么糟糕,这确实会损害您的可扩展性。
According to Stephen Cleary:
根据斯蒂芬·克利里的说法:
do not use Task.Run in the implementation of the method; instead, use Task.Run to call the method.
不要在方法的实现中使用Task.Run;相反,使用 Task.Run 来调用该方法。
You shouldn't wrap your service methods with fake async signatures if the methods are really synchronous, if you don't want to block the UI thread while the heavy method is executing you should use Task.Run when you are calling the services methods from the view model.
I suggest you to read Stephen Cleary series of Task.Run Etiquette articlesin his blog.
如果方法真的是同步的,你不应该用虚假的异步签名包装你的服务方法,如果你不想在执行繁重的方法时阻塞 UI 线程,你应该在调用服务方法时使用 Task.Run视图模型。
我建议您在他的博客中阅读 Stephen Cleary 系列的Task.Run Etiquette 文章。
Consider using async methods for I/O operations
考虑对 I/O 操作使用异步方法
Moreover I can see that the work your service does is not only CPU bound work, if so you should consider to use built in I/O async API method if there is any available over the synchronous you use now (for example Asynchronous File I/O), in this case your methods will be a true async methods and not a fake async wrappers as they are now.
If you will do it your UI thread will not block while the I/O async operation will execute, but if there is still also heavy CPU bound work involved and you don't want to block the UI during the CPU bound work execution you can still use Task.Run when you call the service method from the view model (even though the method signature is already an async one).
More about mixture of synchronous and asynchronous methods in the series of articles above.
此外,我可以看到您的服务所做的工作不仅是 CPU 绑定的工作,如果是这样,您应该考虑使用内置的 I/O 异步 API 方法,如果您现在使用的同步(例如异步文件 I/ O),在这种情况下,您的方法将是真正的异步方法,而不是像现在这样的假异步包装器。
如果你这样做,你的 UI 线程不会在 I/O 异步操作将执行时阻塞,但如果仍然涉及大量 CPU 绑定工作,并且你不想在 CPU 绑定工作执行期间阻塞 UI,你可以当您从视图模型调用服务方法时仍然使用 Task.Run(即使方法签名已经是异步的)。
在上面的系列文章中更多地了解同步和异步方法的混合。
Another great advantage of using bult in async API methods is that if the method is truly async you do not blockany of the ThreadPoolthreads while the async I/O operation is executing and more ThreadPoolthreads are free to do any other work.
This is especially (but not only) important while using async programming in the server side and it can really boost your scalability.
在异步 API 方法中使用 bult 的另一个巨大优势是,如果该方法真正是异步的,则在异步 I/O 操作执行时不会阻塞任何ThreadPool线程,并且更多ThreadPool线程可以自由地执行任何其他工作。
这在服务器端使用异步编程时尤其(但不仅)重要,它可以真正提高您的可扩展性。
Async and MVVM
异步和 MVVM
One last thing, if you are following the MVVM pattern MSDN "async MVVM" articlesare a great reading material you can use.
最后一件事,如果您遵循 MVVM 模式,MSDN“异步 MVVM”文章是您可以使用的绝佳阅读材料。

