2016-10-18 11 views
13

私は、.NET WPFアプリケーションでawait/asyncメカニズムを使い始めました。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において

  • )を我々は意志より少ないタスクを使用する
  • In 2)これは、非同期待ちのアプローチでより「準拠している」と感じています。これにより、一部のメソッドの可視性を変更でき、それでも非同期であることが可能になります。これにより、メソッドいつでも必要に応じて並行して実行できます。
+3

あなたの場合は、UIを応答性にするために 'Task.Run'を使用する必要がありますか?サービスクラスは通常の同期クラスであり、できるだけUIの近くに 'Task.Run'を一度呼び出すことをお勧めします。たとえば、MVVMコマンドハンドラで指定します。 –

+0

ちょうど私の2セントです.2番目のアプローチでは、同期コンテキストを気にしない場合は、 'await'呼び出しごとに' ConfigureAwait(false) 'を使うのを忘れないでください。これは、実行時に毎回コンテキストを切り替えることがないため、小さなパフォーマンス向上をもたらします(特に、多くの 'await'が順番に呼び出される場合)。 – dymanoid

+0

@ YacoubMassadはい、このサービスを使用するたびに、新しいタスクを宣言する必要があり、他のタスクと並行して実行することはできません。 – J4N

答えて

8

どのオプションを選択できますか?

私は、それらの両方が誤解を招くAPIを作成します、あなたのオプションのどちらを使用することになり、あなたのサービスを使用します誰もが、彼は非同期メソッドを使用していると思いますが、真実は偽の署名の後ろの方法が実際にあるということです全く非同期ではありません。
あなたのサービスは、メソッドの実行中にブロックされる別のスレッドに作業をプッシュします。ThreadPool

この原則を使用してサーバー側で悪いとは思わないクライアント側では、実際にスケーラビリティが損なわれる可能性があります。ステファン・クリアリーによると

メソッドの実装でTask.Runを使用しないでください。代わりに、 Task.Runを使用してメソッドを呼び出します。

方法が本当に同期している場合は、重い方法はときに、あなたがTask.Runを使用する必要があります実行している間にUIスレッドをブロックしたくない場合は、偽の非同期署名を使用してサービスメソッドをラップべきではありませんビューモデルからサービスメソッドを呼び出す。

彼のブログで、Task.Run Etiquette articlesのStephen Clearyシリーズを読むことをお勧めします。はそうあなたがI/Oに建て使用することを検討する必要がある場合また、私は、あなたのサービスが行う作業のみCPUバウンドの仕事ではないことがわかりますI/O操作

ための非同期メソッドを使用することを検討して

現在使用している同期よりも利用可能なものがあれば(たとえばAsynchronous File I/O)、この場合、メソッドは真の非同期メソッドになり、今のように偽の非同期ラッパーにはなりません。

I/O非同期操作が実行されている間にUIスレッドがブロックされない場合でも、依然として重いCPUバインドされた作業が含まれていて、CPUバインド中にUIをブロックしたくない場合(たとえメソッドのシグネチャがすでに非同期であっても)ビューモデルからサービスメソッドを呼び出すときに、Task.Runを使用することができます。

上記の一連の記事では、同期メソッドと非同期メソッドの混合について詳しく説明しています。

非同期APIメソッドでBultのを使用することのもう一つの大きな利点は、この方法は、あなたdo not blockThreadPoolスレッドのいずれかの非同期I/O操作が実行され、よりThreadPoolのスレッドが他の仕事をするのは自由ですしながら、非同期(async)本当にある場合。
これは、サーバー側で非同期プログラミングを使用しているときに特に重要ですが、それだけではなく、スケーラビリティを大幅に向上させることができます。

非同期とMVVM

最後に一つ、あなたはMVVMパターンMSDN "async MVVM" articlesを以下している場合には、使用することができます偉大な読み物です。

+0

基本的に、非同期で使用可能なコールスタックの最後にメソッドが1つある場合を除いて、非同期として宣言されたメソッドはありませんか? – J4N

+1

種類が非同期で実装されている場合は、非同期でメソッドをマークするべきではありません。 Task.Runは、UIスレッドから長時間実行しているメソッドを呼び出すときにのみ使用し、ブロックしたくない場合は、メソッドの実装自体でTask.Runを使用しないでください。 – YuvShap

関連する問題