c# - 使用 await-async 的最佳实践,从哪里开始任务?

标签 c# .net wpf asynchronous

我开始在我们的 .Net WPF 应用程序中使用 await/async 机制。

在我的 ViewModel 中,我在服务上调用异步方法。

我的问题是: 是不是比较好

  1. 直接在这个服务里面做一个大的return await Task.Run(()=>{...});
  2. 此服务上的所有子方法是否也是异步的,然后在其中有 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) 中,这感觉更“符合”异步等待方法,这将允许更改某些方法的可见性并仍然是异步的,如果有一天需要,这将允许这些方法并行运行。<

最佳答案

选择哪个选项?

我不会使用你的任何一个选项,它们都会创建一个误导性的 API,每个将使用你的服务的人都会认为他使用了异步方法,但事实是在虚假签名的背后方法实际上根本不是异步的。
您的服务只是将工作推送到另一个 ThreadPool 线程,该线程将在方法执行期间被阻塞。

虽然在客户端听起来并没有那么糟糕,但在服务器端使用此原则确实会损害您的可扩展性。

根据斯蒂芬·克莱里的说法:

do not use Task.Run in the implementation of the method; instead, use Task.Run to call the method.

如果方法真的是同步的,你不应该用伪造的异步签名包装你的服务方法,如果你不想在执行重方法时阻塞 UI 线程,你应该在调用 View 模型中的服务方法。

我建议你在他的博客中阅读 Stephen Cleary 系列的 Task.Run Etiquette articles

考虑对 I/O 操作使用异步方法

此外,我可以看到您的服务所做的工作不仅是 CPU 绑定(bind)工作,如果是这样的话,如果您现在使用的同步方法有任何可用方法(例如 Asynchronous File I/O),您应该考虑使用内置的 I/O 异步 API 方法),在这种情况下,您的方法将是真正的异步方法,而不是像现在这样伪造的异步包装器。

如果您这样做,您的 UI 线程将不会在执行 I/O 异步操作时阻塞,但如果仍然涉及大量 CPU 绑定(bind)工作并且您不想在 CPU 绑定(bind)工作执行期间阻塞 UI,您可以从 View 模型调用服务方法时仍然使用 Task.Run(即使方法签名已经是异步方法签名)。

在上面的系列文章中详细介绍了同步和异步方法的混合。

在异步 API 方法中使用 bult 的另一个巨大优势是,如果该方法是真正异步的,您可以在执行异步 I/O 操作时使用 do not block 任何 ThreadPool 线程以及更多 ThreadPool 线程可以自由地做任何其他工作。
这在服务器端使用异步编程时尤其(但不仅)重要,它可以真正提高您的可扩展性。

异步和 MVVM

最后一件事,如果您遵循 MVVM 模式,MSDN "async MVVM" articles 是您可以使用的很好的阅读 Material 。

关于c# - 使用 await-async 的最佳实践,从哪里开始任务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40104279/

相关文章:

c# - DPI 百分比缩放到实际 DPI 值

c# - 无法隐式转换类型 'System.Linq.IQueryable<AnonymousType#1>'

C# 对 SSPI 的调用失败,请参阅内部异常 - 无法联系本地安全机构

c# - RESTful API 设计

.net - Windows Azure Web 角色缓存(预览版) "hangs"使模拟器陷入部署循环

c# - 如何在 ICSharpCode.AvalonEdit.TextEditor 中更改文本颜色?

c# - c#中JSON的反序列化

c# - 使用 EventAggregator 和 ViewModel 注册类型

c# - JsonServiceClient 似乎未包含在程序集中

c# - WPF 用户控件绑定(bind)