18

Async/Await を使用して UI スレッドを解放し、マルチスレッドを実現します。例外が発生したときに問題が発生しました。Call Stack私の非同期部分の は常に で始まりますが、ThreadPoolWorkQue.Dipatch()これはあまり役に立ちません。

MSDN の記事Andrew Stasyuk を見つけました。それについての非同期因果連鎖追跡ですが、私が理解しているように、すぐに使用できるソリューションではありません。

Async/Await でマルチスレッドを使用する場合、最適で最も簡単なデバッグ方法は何ですか?

4

1 に答える 1

20

あなたが見つけた記事は、コール スタックが私たちのほとんどが思っているように機能しない理由をうまく説明しています。技術的には、コール スタックは、現在のメソッドの後にコードが戻る場所を示すだけです。言い換えれば、コールスタックは「コードがどこから来たのか」ではなく、「コードがどこへ行くのか」です。

興味深いことに、この記事では解決策について言及していますが、詳しくは説明していません。解決策を詳しく説明するブログ投稿がありCallContextます。基本的に、論理呼び出しコンテキストを使用して、独自の「診断コンテキスト」を作成します。

CallContextこの記事で紹介したソリューションよりも、このソリューションの方が気に入っています。これは、すべての形式のasyncコード ( のような fork/join コードを含むTask.WhenAll) で機能するためです。

これは私が知っている最善の解決策です (プロファイリング API にフックするなど、非常に複雑なことを行う場合を除きます)。CallContextアプローチの注意事項:

  • .NET 4.5 フルでのみ動作します。Windows ストア アプリ、.NET 4.0 などはサポートされません。
  • コードを手動で「インストルメント化」する必要があります。私の知る限り、自動的に注入する方法はありません。
  • 例外は、論理呼び出しコンテキストを自動的にキャプチャしません。したがって、このソリューションは、例外がスローされたときにデバッガーに侵入する場合には問題なく機能しますが、別の場所で例外をキャッチしてログに記録するだけの場合にはあまり役に立ちません。

コード (不変コレクション NuGet ライブラリに依存):

public static class MyStack
{
    private static readonly string name = Guid.NewGuid().ToString("N");

    private static ImmutableStack<string> CurrentContext
    {
        get
        {
            var ret = CallContext.LogicalGetData(name) as ImmutableStack<string>;
            return ret ?? ImmutableStack.Create<string>();
        }

        set
        {
            CallContext.LogicalSetData(name, value);
        }
    }

    public static IDisposable Push([CallerMemberName] string context = "")
    {
        CurrentContext = CurrentContext.Push(context);
        return new PopWhenDisposed();
    }

    private static void Pop()
    {
        CurrentContext = CurrentContext.Pop();
    }

    private sealed class PopWhenDisposed : IDisposable
    {
        private bool disposed;

        public void Dispose()
        {
            if (disposed)
                return;
            Pop();
            disposed = true;
        }
    }

    // Keep this in your watch window.
    public static string CurrentStack
    {
        get
        {
            return string.Join(" ", CurrentContext.Reverse());
        }
    }
}

使用法:

static async Task SomeWorkAsync()
{
    using (MyStack.Push()) // Pushes "SomeWorkAsync"
    {
        ...
    }
}

更新: PostSharp を使用してプッシュとポップを自動的に挿入するNuGet パッケージ (ブログで説明)をリリースしました。したがって、適切なトレースを取得することは、はるかに簡単になるはずです。

于 2013-04-09T12:21:50.250 に答える