2

VisualStudio2012を使用してASPWebアプリケーションを作成しました。

デフォルトのページを次のように変更した場合:

public partial class _Default : Page
{
    static async Task PerformSleepingTask()
    {
        Action action = () =>
        {
            Thread.Sleep(TimeSpan.FromSeconds(0.5));
            int dummy = 3; // Just a nice place to put a break point
        };
        await Task.Run(action);
    }


    protected void Page_Load(object sender, EventArgs e)
    {
        Task performSleepingTask = PerformSleepingTask();
        performSleepingTask.Wait();
    }
}

それへの呼び出しperformSleepingTask.Wait()で無期限にハングします。


興味深いことに、これをweb.configで設定すると、次のようになります。

<appSettings>

    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="false" />
</appSettings>

その後、それは機能します。このWait関数は、別のスレッドでスリープが終了するのを待ってから続行します。


誰かが説明できますか:

  • なぜハングするのですか?
  • なぜ彼らは呼ばれるものを持っているのTaskFriendlySynchronizationContextですか?(タスクがハングする原因になることを考えると、「フレンドリー」とは言いません)

  • asyncページハンドラメソッドからメソッドを呼び出すための「ベストプラクティス」はありますか?

これが私が思いついた実装で、機能しますが、不器用なコードのように感じます:

    protected void Page_Load(object sender, EventArgs e)
    {
        ManualResetEvent mre = new ManualResetEvent(false);
        Action act = () =>
        {
            Task performSleepingTask = PerformSleepingTask();
            performSleepingTask.Wait();
            mre.Set();
        };
        act.BeginInvoke(null, null);
        mre.WaitOne(TimeSpan.FromSeconds(1.0));
    }
4

1 に答える 1

4

なぜハングするのですか?

Task代表は、それが戻ることができるように、PerformSleepingTaskその後に再開しようとしています。への呼び出しによってブロックされている ASP.NET 要求コンテキストに再度入ろうとしています。ブログで説明しているように、これはデッドロックを引き起こします。awaitPerformSleepingTaskWait

デッドロックを回避するには、次のベスト プラクティスに従ってください。

  1. 下まで使用asyncしてください。asyncコードをブロックしないでください。
  2. ConfigureAwait(false)「ライブラリ」メソッドで使用します。

なぜ彼らはと呼ばれるものを持っているのTaskFriendlySynchronizationContextですか?(タスクがハングすることを考えると、「フレンドリー」とは言えません)

TaskFriendlySynchronizationContextは新しいAspNetSynchronizationContext(.NET 4.0TaskFriendlySynchronizationContextは名前が変更されましたLegacyTaskFriendlySynchronizationContext) を使用し、新しいasync認識パイプラインも使用します。

これについて 100% 確信があるわけではありませんが、レガシーSyncCtxで機能する理由Page_Loadは、古いパイプラインがまだ SyncCtx を配置していないためだと思います。ただし、なぜこのように動作するのかはわかりません(そうでない限りPage.Asyncfalse

ページ ハンドラー メソッドから非同期メソッドを呼び出すための「ベスト プラクティス」はありますか?

絶対に。イベント ハンドラを作成するかasync void、またはRegisterAsyncTask(new PageAsyncTask(...));. 最初の方法は簡単ですが、ASP.NET チームは 2 番目の方法を好んで使用します。

于 2012-10-03T10:52:18.190 に答える