Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/292.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用await async的最佳实践,从何处开始任务?_C#_.net_Wpf_Asynchronous - Fatal编程技术网

C# 使用await async的最佳实践,从何处开始任务?

C# 使用await async的最佳实践,从何处开始任务?,c#,.net,wpf,asynchronous,C#,.net,Wpf,Asynchronous,我开始在.NETWPF应用程序中使用wait/async机制 在我的ViewModel中,我正在调用一个服务的异步方法 我的问题是: 这样更好吗 直接在这个服务内部,做一个大的返回等待任务 使此服务上的所有子方法都是异步的,然后在此子方法中有任务。运行 举例来说: (一) 公共类服务:iSeries{ 公共异步任务(SomeParameter){ 返回等待任务。运行(()=>{ CopyStuff(参数A); 升级材料(参数B); 返回重载(parameter.C) }); } 私有void C

我开始在.NETWPF应用程序中使用wait/async机制

在我的ViewModel中,我正在调用一个服务的异步方法

我的问题是: 这样更好吗

  • 直接在这个服务内部,做一个大的
    返回等待任务
  • 使此服务上的所有子方法都是异步的,然后在此子方法中有
    任务。运行
  • 举例来说:

    (一)

    公共类服务: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方法更“兼容”,这将允许更改某些方法的可见性,并且仍然是异步的,这将允许这些方法在某一天需要时并行运行

    选择哪个选项?

    我不会使用你的两个选项,它们都会创建一个误导性的API,使用你的服务的每个人都会认为他使用了异步方法,但事实是,假签名背后的方法实际上根本不是异步的。
    您的服务只是将工作推送到另一个
    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 
        }   
    }