2015-10-15 13 views
5

私の望みは、長期実行のI/O操作を非同期に行うMVCコントローラのアクションを作成することです。私の目標は、この長時間実行されるメソッドが完了している間にASP.Netスレッドプール内のスレッドを縛るのを避けることです。ASP.Net MVCコントローラの動作方法非同期

アクションは2回コールします。

最初の呼び出しは、非同期メソッドを含まないサードパーティ製のdllです。このdllは、独自のデータベースから読み取り、かなり複雑なCPUバウンド処理を行います。それは戻ってくるのに数秒かかることがあります。

2番目の呼び出しでは、最初の呼び出しの結果が、Entity Frameworkを使用してデータベースクエリに渡されるパラメータとして使用されます。私は3rdPartyComponentのawaitableに電話をしたいと思い

public async Task<ActionResult> MyActionAsync(arg1, arg2) 
{ 
    var parameters = 3rdPartyComponent.TakesLongTime(arg1, arg2); 

    Task<List<MyClass>> genericList = null; 

    using (DbContexts.MyDbContext db = new DbContexts.MyDbContext()) 
     { 
      genericList = await db.Database.SqlQuery<MyClass>(sql,parameters).ToListAsync(); 
     } 

    return View("MyView", genericList); 
} 

簡体字、これはアクションです。私の最初のアイデアは、これを行うことだった。

var parameters = await Task.Run(() => 3rdPartyComponent.TakesLongTime()).ConfigurateAwait(false); 

を私はいくつかの主題の専門家がTask.Runを(使用していることを断固述べる読んだ)asp.net MVCアクション内部の反生産的であると行われるべきではありません。

3rdPartyComponentはコンパイルされたコードの黒いボックスで、非同期メソッドを追加するために変更することはできません。

3rdPartyComponentの呼び出しを待つことができる方法はありますか?そのため、アクション全体がasp.netスレッドプール内のスレッドを縛らずに実行されますか?

+0

* asp.net MVCアクション内のTask.Run()は生産性が悪く、決して実行しないでください*。これは真実ではありません。あなたがこれをやりたいことがあるかもしれない多くの場合があります。私はあなたがこれをいつもしなければならないと言っているわけではありませんが、別スレッドを生成したい場合はどうしてですか? – Liam

+1

こんにちはTom、これを読んでください:http://blog.stephencleary.com/2013/08/startnew-is-dangerous.htmlそして、あなたがあなたの最適化において時期尚早であるかどうかを検討してください。交通量の多い方法では、これが不要なステップである可能性は確かです。 (おそらくTask.Factory.StartNewを使用して、ThreadPoolの作業をスケジュールするためにTaskCreationOptionsを提供できるようになるでしょう) – spender

+0

@spender、これは大量のトラフィックの方法です。 –

答えて

6

最初の呼び出しは、非同期メソッドを含まないサードパーティ製のdllです。このdllは、独自のデータベースから読み取り、かなり複雑なCPUバウンド処理を行います。

私は3rdPartyComponentの呼び出しを待ち望んでいます。

3rdPartyComponentの呼び出しを待つことができる方法はありますか?そのため、アクション全体がasp.netスレッドプール内のスレッドを縛らずに実行されますか?

コードは既に得られるほど良好です。Task.RunでもTask.Factory.StartNewでも、(たとえあなたがLongRunningフラグを渡しても)何かの利点があります。

サードパーティ製のdllはCPUバインドされたコードなので、スレッドが必要です。たとえそれを変更できたとしても、dbアクセス(I/O作業)を非同期にすることしかできませんでした。 CPUの作業は定義によって同期しています。あなたの説明からは、CPUの作業が大部分の時間と同じように聞こえます。

ASP.NETのTask.Run(さらに悪いのはTask.Factory.StartNew)を回避するという全般的なポイントは、効率の低い動作の原因となることです。 ASP.NETリクエストスレッドを解放することによって、スレッドプールが使用されていない間にスレッドプールに返すだけです。 ASP.NETのリクエストスレッドに関して魔法や特別なことは何もありません。したがって、Task.Runは、別のスレッドプールスレッドに切り替えることによって1つのスレッドプールスレッドを解放し、をLongRunningとすると、新しいスレッド全体を作成し、その作業をスケジューリングし、最後にそのスレッドを破棄することによってスレッドプールスレッドを解放します動作は文書化も指定もされていませんが、現在の観察された動作です)。

最後に、不必要なスレッドスイッチ(そして、StartNewの場合、余分なスレッド全体)が発生するだけです。 ASP.NETは、同期作業と非同期作業の両方を処理するように設計されています。同期コードがある場合は、コードが既に実行しているのとまったく同じように、コードを直接実行するだけです。

1

はい、私は、非同期サーバーメソッドでTask.Runを使用することは、あなたが予定していた作業がThreadPoolにちょうど再配置されてしまい、反パターンであると主張します。 。ネットゲインゼロ(ThreadPoolでコールバックをスケジューリングするオーバーヘッドを引いた値)。

私の最初の考えは

Task.Factory.StartNew(action,TaskCreationOptions.LongRunning) 

​​で仕事をオフに解雇しているが仕事ではなくThreadPoolのより新しいスレッドで行われるべきであるというヒントです。

...これはトラフィック量の多い方法である場合、スレッドを作成する速度が速くなり、スレッドプールの管理上の利点が失われてしまう危険性があります。

トラフィックが本当にあなたが言うほど高く、順序であるかもしれない特別な治療のこの種、スロットリングおよび/またはcacheingのいくつかの並べ替えを必要とする...しかし、それは別の質問になるなら...

+0

...はい、あなたは本当にそのような "キャッシュ"を綴ることができます! – spender

+0

私はGoogleの "キャッシュ"と私に "キャッシングの結果を表示"を教えてくれます:) – DavidG

+0

+1のTaskCreationOptions。LongRunningヒント。しかし、私はこの質問に対する真の答えが「このアクションを非同期化しようとしないでください。修正するよりも多くの問題を引き起こす」と思います。 –

関連する問題