次のことを考えてみてください(デフォルトのMVCテンプレートに基づく)。これは、バックグラウンドで発生するいくつかの「もの」の簡略化されたバージョンです。正常に完了し、期待される結果を示します20:
public ActionResult Index()
{
var task = SlowDouble(10);
string result;
if (task.Wait(2000))
{
result = task.Result.ToString();
}
else
{
result = "timeout";
}
ViewBag.Message = result;
return View();
}
internal static Task<long> SlowDouble(long val)
{
TaskCompletionSource<long> result = new TaskCompletionSource<long>();
ThreadPool.QueueUserWorkItem(delegate
{
Thread.Sleep(50);
result.SetResult(val * 2);
});
return result.Task;
}
ただし、ここでいくつかasync
をミックスに追加すると、次のようになります。
public static async Task<long> IndirectSlowDouble(long val)
{
long result = await SlowDouble(val);
return result;
}
ルートの最初の行を次のように変更します。
var task = IndirectSlowDouble(10);
その後、それは機能しません。代わりにタイムアウトします。ブレークポイントを追加するreturn result;
と、メソッド内はルートがすでに完了した後async
にのみ発生します。基本的に、システムはリクエストが終了するまで、スレッドを使用して操作を再開することを望まないようです。さらに悪いことに、使用した(またはアクセスした)場合は、完全にデッドロックになります。async
.Wait()
.Result
だから:それは何ですか?明らかな回避策は「関与しない」ですasync
が、ライブラリなどを使用する場合は簡単ではありません。最終的には、との間に機能的な違いはありません(構造的な違いは明らかですが)。SlowDouble
IndirectSlowDouble
注:コンソール/winformなどでまったく同じことが正常に機能します。