ASP.NET MVCで非同期コントローラーを使用する必要があるのはいつですか?


215

ASP.NET MVCで非同期アクションを使用するいくつかの懸念があります。アプリのパフォーマンスが向上するのいつですか?

  1. ASP.NET MVCのどこでも非同期アクションを使用するのは良いことですか?
  2. 待機可能なメソッドについて:(EF / NHibernate /その他のORMを介して)データベースにクエリを実行する場合は、async / awaitキーワードを使用する必要がありますか?
  3. 何回で非同期データベースを照会するためのawaitキーワードを使用することができる1つのアクションメソッド?

回答:


109

非同期アクションメソッドは、アクションがいくつかの独立した長時間実行オペレーションを実行する必要がある場合に役立ちます。

AsyncControllerクラスの一般的な用途は、長時間実行されるWebサービスの呼び出しです。

データベース呼び出しを非同期にする必要がありますか?

IISスレッドプールは、多くの場合、データベースサーバーよりも多くの同時ブロッキング要求を処理できます。データベースがボトルネックである場合、非同期呼び出しはデータベースの応答を高速化しません。スロットルメカニズムがなければ、非同期呼び出しを使用して、圧倒されたデータベースサーバーにさらに多くの作業を効率的にディスパッチしても、データベースへの負担が増えるだけです。DBがボトルネックである場合、非同期呼び出しは特効薬ではありません。

あなた12の参照を見る必要があります

@PanagiotisKanavosのコメントから派生:

さらに、非同期は並列を意味しません。非同期実行により、貴重なスレッドプールスレッドが外部リソースのブロックから解放され、複雑さやパフォーマンスコストが発生しません。これは、同じIISマシンがより多くの同時要求を処理できることを意味します。

また、ブロッキング呼び出しは、CPUを集中的に使用するスピンウェイトで始まることも考慮する必要があります。ストレス時に、呼び出しをブロックすると、遅延の増大とアプリプールのリサイクルが発生します。非同期呼び出しは単にこれを回避します


27
非同期、IIS、およびデータベースに関しては、ブログの投稿は非常に古く、ここでの結論は間違っています。IISはデータベースよりもはるかに大きな負荷を処理する必要があり、スレッドプールスレッドは制限され、長い要求キューは500につながる可能性があります。IOを待機している間にスレッドを解放するものは何でも有益です。リンクでさえ、OPが求めたものではありません。実際、同じ著者ができる限り非同期DBメソッド使用する必要があると書いています
Panagiotis Kanavos

30
さらに、非同期は並列を意味しません。非同期実行により、貴重なスレッドプールスレッドが外部リソースのブロックから解放され、複雑さやパフォーマンスコストが発生しません。これは、同じIISマシンより多くの同時要求を処理できることを意味します
Panagiotis Kanavos 2015年

5
また、ブロッキング呼び出しは、CPUを集中的に使用するスピンウェイトで始まることも考慮する必要があります。ストレス時に、呼び出しをブロックすると、遅延の増大とアプリプールのリサイクルが発生します。非同期呼び出しは単にこれを避けます
Panagiotis Kanavos

1
これは受け入れられた回答であり、ほとんどの人にとっては一番上なので、実行時間と並列実行に関する2番目の最初の段落を削除することをお勧めします。これは非同期とは関係ありません。最後にメモがあることに気づきましたが、それかなり誤解を招くものです。
ロブ

1
非同期実行は、実装の最下部まで本当に非同期である場合にのみスレッドを解放し、いくつかのコールバックメカニズムを使用して準備ができていることを通知し、新しいスレッドを起動してコンテキストを切り替えて結果を処理します。したがって、このコンテキスト切り替え/新しいスレッドの作成が、単一のスレッドで結果を待つだけの場合よりも効率的であるかどうかはわかりませんか?とにかく、実行時間の長いWebサービスコールは悪い考えです。信頼できるバックグラウンドサービスにオフロードして、クライアントに数分、数時間、または数日で到着する可能性がある結果を確認させたいと思います。
JustAMartin

229

この件に関する私のMSDNの記事が参考になります。この記事async、ASP.NETでの使用方法だけでなく、ASP.NETでいつ使用すべき説明するためasyncに多くのスペースを取った。

ASP.NET MVCで非同期アクションを使用するいくつかの懸念があります。アプリのパフォーマンスが向上する場合とそうでない場合

まず、async/ awaitスレッドを解放することのすべてであることを理解してください。GUIアプリケーションでは、主にGUIスレッドを解放してユーザーエクスペリエンスを向上させることを目的としています。サーバーアプリケーション(ASP.NET MVCを含む)では、主に要求スレッドを解放してサーバーをスケーリングできるようにします。

特に、それはしません:

  • 個々のリクエストをより速く完了させます。実際、完了するのは遅くなります(ほんの少しだけ)。
  • を押すと、発信者/ブラウザに戻りますawaitawaitブラウザーではなく、ASP.NETスレッドプールにのみ「委譲」します。

最初の質問は、ASP.NET MVCのあらゆる場所で非同期アクションを使用するのは良いことですか?

I / Oを行うすべての場所で使用するのが良いと思います。ただし、必ずしも有益であるとは限りません(以下を参照)。

しかし、それはだ、悪い CPUバウンドメソッドのためにそれを使用します。開発者は、コントローラーをasync呼び出すだけでメリットを得ることができると考える場合がありますがTask.Run、これは恐ろしい考えです。そのコードは、別のスレッドを使用することによって要求スレッドを解放することになるため、まったくメリットがありません(実際、追加のスレッドスイッチのペナルティを取っています)。

(EF / NHibernate /その他のORMを介して)データベースにクエリを実行する場合、async / awaitキーワードを使用する必要がありますか?

利用可能な待機可能なメソッドを使用できます。現在、主要なプレーヤーのほとんどがサポートasyncしていますが、サポートしていないものもあります。ORMがをサポートしていない場合はasync、それをTask.Runそのようなものでラップしようとしないでください(上記を参照)。

「使用できます」と言ったことに注意してください。単一のデータベースバックエンドを備えたASP.NET MVCについて話している場合、(ほぼ確実に)からスケーラビリティのメリットを得ることはできませんasync。これは、IISがSQLサーバー(または他の従来のRDBMS)の単一のインスタンスよりもはるかに多くの同時要求を処理できるためです。ただし、SQLサーバークラスター、Azure SQL、NoSQLなど、バックエンドがよりモダンであり、バックエンドがスケーリング可能で、スケーラビリティのボトルネックがIISである場合、からスケーラビリティのメリットを得ることができますasync

3番目の質問-待機キーワードを使用して、1つの単一アクションメソッドでデータベースに非同期でクエリを何回実行できますか?

好きなだけ。ただし、多くのORMには接続ごとに1つの操作のルールがあることに注意してください。特に、EFはDbContextごとに1つの操作のみを許可します。これは、操作が同期か非同期かに関係なく当てはまります。

また、バックエンドのスケーラビリティについても念頭に置いてください。SQL Serverの単一インスタンスを使用していて、IISがSQLServerをフル稼働に保つことができる場合、SQLServerへのプレッシャーを2倍または3倍にしても、まったく役に立たないでしょう。


2
@seebiscuit:(適切な非同期)I / Oを行う場合、スレッドは使用されません。私が持っているブログの記事に詳細に入ります。
Stephen Cleary

2
IISと1つのSQL Serverインスタンスで処理できる要求の数はいくつですか。これらの番号を見つけるにはどうすればよいですか?
MOD

1
@MOD:構成とハードウェアに依存します。これらの数値を見つける唯一の方法は、自分のサーバーで負荷テストを行うことです。
Stephen Cleary

1
@Flezcano:CPUで完全に実行されるメソッド。つまり、I / Oやブロックは行いません。
Stephen Cleary

1
申し訳ありませんが、SOは理解しようとしているこの2つのライナーの質問を受け入れません.1000人のユーザーによって同時に呼び出される1つのWeb APIエンドポイントがある場合、このことについて調査していたとき、このエンドポイントは可能になりますこの千のリクエストのそれぞれをサーバーに送るか、1000のリクエストを処理するために非同期にする必要がありますか?
ラーニングオーバーシンカーの混乱

21

ASP.NET MVCのどこでも非同期アクションを使用するのは良いことですか?

プログラミングでいつものように、それは依存します。特定の道を行くときは常にトレードオフがあります。

async-awaitサービスへの同時リクエストを受信することがわかっていて、適切にスケールアウトできるようにしたい場合に最適です。async-awaitスケールアウトにどのように役立ちますか?ネットワーク呼び出しやデータベースのヒットなど、非同期IO呼び出しを同期的に呼び出すと、実行を担当する現在のスレッドは、要求が完了するのを待ってブロックされます。を使用async-awaitすると、フレームワークがステートマシンを作成できるようになります。これにより、IO呼び出しが完了した後、中断したところからメソッドが実行を継続します。

注意すべき点は、この状態マシンにはわずかなオーバーヘッドがあることです。メソッドを非同期にしても、実行が速くなるわけではありません。これは、多くの人が理解している誤解や誤解の重要な要素です。

使用時に考慮すべきもう1つのことasync-awaitは、それが完全に非同期であるという事実です。つまり、非同期がコールスタック全体を突き抜けて、buttomに到達することがわかります。つまり、同期APIを公開したい場合、非同期同期がうまく混ざらないため、特定の量のコードが重複することがよくあります。

(EF / NHibernate /その他のORMを介して)データベースにクエリを実行する場合、async / awaitキーワードを使用する必要がありますか?

非同期IO呼び出しを使用する方法を選択する場合は、はい、それasync-awaitが適切な選択肢になります。最新のデータベースプロバイダーがTAP(タスク非同期パターン)を実装する非同期メソッドを公開しているためです。

awaitキーワードを使用して、1つの単一アクションメソッドでデータベースを非同期にクエリできる回数は何回ですか?

データベースプロバイダーによって指定されたルールに従う限り、必要な数だけ使用できます。非同期呼び出しの数に制限はありません。互いに独立していて同時に実行できるクエリがある場合、それぞれに対して新しいタスクをスピンし、を使用await Task.WhenAllして両方が完了するのを待つことができます。


2
非同期のdb呼び出しは高速には実行されませんが、スレッドプールのスレッドが無駄にならないため、同じIISマシンでより多くのリクエストを処理できます。また、ブロッキング呼び出しは、実際にブロックする前に、CPUを集中的に使用するスピンウェイトで始まるため、CPUコストも削減されます。高負荷の状況では、これはマシンの苦労または故障とリサイクルの違いになる可能性があります
Panagiotis Kanavos

@PanagiotisKanavos私が知っている、私が言ったことからそれは不明瞭でしたか?
Yuval Itzchakov

1
答えはIISの詳細には触れていません。メルトダウン/リサイクルのシナリオは、全体を通して非同期を使用する主な理由です。それを経験したことがない人はおそらくそれscale out wellが意味するかもしれないことを理解しないでしょうyour server won't die under load。または、それが原因である可能性がありますonce burned ...
Panagiotis Kanavos

7

私の5セント:

  1. async/awaitDBや外部サービスWebサービスなどのIO操作を行う場合にのみ使用します。
  2. 常にDBへの非同期呼び出しを優先します。
  3. DBをクエリするたび。

PSポイント1には例外的なケースがありますが、そのためには非同期内部について十分に理解している必要があります。

追加の利点として、必要に応じていくつかのIO呼び出しを並行して実行できます。

Task task1 = FooAsync(); // launch it, but don't wait for result
Task task2 = BarAsync(); // launch bar; now both foo and bar are running
await Task.WhenAll(task1, task2); // this is better in regard to exception handling
// use task1.Result, task2.Result

6

asyncアクションは、アクションがDBまたはネットワークバインドされた呼び出しに対していくつかのI \ O操作を行うときに最も役立ちます。ここで、要求を処理するスレッドは、呼び出したDBまたはネットワークバインドされた呼び出しから応答を受け取る前に停止します。それらと一緒にawaitを使用することをお勧めします。これにより、アプリケーションの応答性が大幅に向上します(DBまたはそのような他の操作の待機中にストールするASP入出力スレッドが少なくなるため)。私のすべてのアプリケーションでは、DBへの多くの呼び出しが非常に必要なときはいつでも、それらを常にawaiatableメソッドでラップし、それをawaitキーワードで呼び出しました。


5

ご存じのとおり、MVCは非同期コントローラーをサポートしているので、それを利用する必要があります。コントローラーが長い操作を実行する場合(ディスクベースのI / Oまたは別のリモートサービスへのネットワーク呼び出しなど)、要求が同期的に処理されると、IISスレッドは常にビジー状態になります。その結果、スレッドは時間のかかる操作が完了するのを待っているだけです。最初に要求された操作の進行中に他の要求を処理することで、より効果的に利用できます。これにより、より多くの同時リクエストに対応できます。Webサービスは非常にスケーラブルであり、C10kの問題に簡単に遭遇することはありません。dbクエリにはasync / awaitを使用することをお勧めします。はい、必要に応じて何度でも使用できます。

優れたアドバイスについては、こちらご覧ください。


3

私の経験では、今日、多くの開発者async/awaitがコントローラーのデフォルトとして使用しています。

私の提案は、それがあなたを助けることがわかっているときだけそれを使うことです

その理由は、Stephen Clearyや他の人がすでに述べたように、解決するのではなく、パフォーマンスの問題を引き起こす可能性があり、特定のシナリオでのみ役立つ場合があるためです。

  • 高トラフィックコントローラ
  • スケーラブルなバックエンド

2

ASP.NET MVCのどこでも非同期アクションを使用するのは良いことですか?

特に、大量のデータと計算操作で発生するワーカープロセスレベルでパフォーマンスの問題が発生している場合は、非同期メソッドを使用できる場所にそうすることをお勧めします。それ以外の場合は、単体テストでキャストが必要になるため不要です。

待機可能なメソッドについて:(EF / NHibernate /その他のORMを介して)データベースにクエリを実行する場合は、async / awaitキーワードを使用する必要がありますか?

はい。ワーカープロセスレベルでのパフォーマンスの問題を回避するために、DB操作にはできるだけ非同期を使用することをお勧めします。EFは、次のようなほとんどの操作に対して多くの非同期の代替手段を作成していることに注意してください。

.ToListAsync()
.FirstOrDefaultAsync()
.SaveChangesAsync()
.FindAsync()

awaitキーワードを使用して、単一のアクションメソッドでデータベースに非同期でクエリを何度実行できますか?

空は限界です


ほとんどのWebアプリのビジネスロジックは、通常、高度にシーケンシャルな操作を必要とするため、ほとんどの場合、並列プロセス間のジャンプは、データベースリクエストを直接処理しないWebリクエスト/ワーカープロセス管理の最上位レベルでのみ実行できます。DBクエリを非同期で処理することが実際に良いアイデアである典型的なWebアプリケーションの実例をいくつか実際に見たいと思います。
JustAMartin
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.