2016-09-22 11 views
1

私はこのように、これらのもののための非同期バージョンを含むいくつかの方法でリポジトリを生成しようとしているとしています:非同期式はC#

長所は何

と:

//Method 1 
    public static List<MyEntity> GetMyEntityByDate(MyContextType context) 
    { 
     var tmpMov = context.MyEntity 
      .AsNoTracking() 
      .ToList(); 

     return tmpMov; 

    } 

    //Method 2 V1 
    public async static List<MyEntity> GetMyEntityByDateAsync(MyContextType context) 
    { 
     var tmpMov = await context.MyEntity 
      .AsNoTracking() 
      .ToListAsync(); 

     return tmpMov; 
    } 

    //Method 2 V2 
    public async static List<MyEntity> GetMyEntityByDateAsync(MyContextType context) 
    { 
     List<MyEntity> tmpMov = null; 
     await Task.Factory.StartNew(() => { 
      tmpMov = GetMyEntityByDate(context); 
     }); 

     return tmpMov; 
    } 

は今、私はいくつかの質問を持っていますパフォーマンスと流暢性の観点から、方法2 V1対方法2 V2を使用するのはどうですか?

私はリポジトリパターンを実装しているので、少ないコードを書きたいと思っています。これは、私がV2を検討している理由です。

しかし、私はの非同期で貧弱な経験があり、私の目標は邪悪なものです。

+1

V1データベースクエリを(理由ToListAsyncの)際V2はので、実際には非同期のいずれかの利点を使用しませんしません(プラススレッドプールをブロックしながら、async IOの活用しますレスポンスを待っている間は何もしません)。要するに、V2については忘れてV1を使用してください。 – Evk

+0

最初は 'sync'の方法です.2番目の場合は、非同期でリストに変換するだけで、大きな利益は得られません。また、2v2では非同期オーバーシンクと呼ばれるので、TaskよりTask.FromResult()を使う方が良いです。 Factory.StartNew() ' – Fabjan

+0

'最高のパフォーマンス '<=はパフォーマンスを定義しますか?これがWebサーバー用で、要求を処理できるスレッドの数を最大にしたい場合は、v2( 'ToListAsync'を使用)が最適です。一般的なオーバーヘッド(Webフォームやコンソールアプリケーションの場合)を参照している場合、v1はおそらくより良い一致です。 V3は全く考慮されてはいけません。 – Igor

答えて

2

パフォーマンスと流暢性の面で、方法2 V1と方法2 V2を使用することの長所と短所は何ですか?

方法2は、適切な非同期メソッドです。方法2 V2はTaskScheduler.Current(現在のタスクスケジューラがない場合はスレッドプール)上でブロック作業を実行する偽非同期メソッドです。

このように、V2はベストプラクティスnot to expose asynchronous wrappers for synchronous methodsと違反します。

私はリポジトリパターンを実装しており、少ないコードを書いているので、V2を検討している理由を維持するために1つのクエリしかありません。

私は理想的なシナリオは実際に方法2 V1を公開し、方法1を完全に取り除くことだと思います。データベースのクエリは本来I/Oベースなので、APIは当然非同期です。

には、実際にの同期APIと非同期APIの両方が必要な場合は、"bool argument hack" as described in my MSDN article on Brownfield Async Developmentを使用することをおすすめします。

これは、次のようになります。

private async static Task<List<MyEntity>> DoGetMyEntityByDateAsync(MyContextType context, bool sync) 
{ 
    var query = context.MyEntity 
     .AsNoTracking(); 
    return sync ? 
     query.ToList() : 
     await query.ToListAsync(); 
} 

public static Task<List<MyEntity>> GetMyEntityByDateAsync(MyContextType context) 
{ 
    return DoGetMyEntityByDateAsync(context, sync: false); 
} 

public static List<MyEntity> GetMyEntityByDate(MyContextType context) 
{ 
    return DoGetMyEntityByDateAsync(context, sync: true).GetAwaiter().GetResult(); 
} 
6

使用context.MyEntity.ToList()は、データベースがクエリの実行を終了するまで、現在のスレッドをビジーに保ちます。

await context.MyEntity.ToListAsync();を使用すると、データベースがクエリの実行を終了するまで、現在のスレッドが解放されます。

await Task.Factory.StartNew(() => { });を使用すると、現在のスレッドは解放されますが、新しいスレッドが作成され、DBが実行を終了するまでビジー状態を維持します。

+0

そしてあなたのためにそれをする最善の方法は何ですか? –

+0

'//方法2のV1'は私の意見では最良の選択です。私もアプリケーションでこのパターンを実装しています。 – Catalin

+0

@JuanPabloGomez - ToListAsync(またはライブラリ呼び出しで非同期の部分)の後に '.ConfigureAwait(false)'を追加することをお勧めします。これにより、通話の効率が高まり、通話元のスレッドで再加入する必要がないことがコールバックに指示されます。ですから、このような図書館の文脈では、それを追加するのは良いことです。 MvcまたはWeb APIコントローラのアクションメソッドのように、スレッドコンテキストが必要な場所では使用しないでください。 – Igor