2013-04-09 22 views
15

Async/Awaitを使用してUIスレッドを解放し、マルチスレッドを実現します。今私は例外を打つときに問題がある。私の非同期部品のCall Stackは、常にThreadPoolWorkQue.Dipatch()で始まります。Async/Await(コールスタック)の例外のデバッグ

私はMSDN-Article Andrew Stasyuk. Async Causality Chain Trackingを見つけましたが、私が理解しているように、すぐに使用できるソリューションではありません。

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

答えて

18

あなたが見つけた記事は、私たちの大部分のようにコールスタックがうまくいかない理由を説明してくれます。技術的には、コールスタックは、コードが現在のメソッドの後にどこに戻ってくるかを伝えます。言い換えれば、コールスタックは「コードがどこから来たか」ではなく、「コードがどこに行くのか」です。興味深いことに、この記事では合格の解決策について言及していますが、解説しません。私はa blog post that goes explains the CallContext solution in detailです。基本的には、論理コールコンテキストを使用して独自の「診断コンテキスト」を作成します。

は、私はそれが仕事が asyncコードのすべての形式( Task.WhenAllのようなコードに参加/フォークを含む)になるんので、記事で紹介したソリューションよりも CallContextソリューションの方が好き。

これは私が知っている最良の解決策です(プロファイリングAPIへのフックのような非常に複雑なこと以外)。 CallContextの警告:

  • これは.NET 4.5でのみ動作します。 Windows Storeアプリケーション、.NET 4.0などはサポートされていません
  • コードを手動でインストルメントする必要があります。 AFAIKを自動的に挿入する方法はありません。
  • 例外は、論理呼び出しコンテキストを自動的に取得しません。したがって、例外がスローされたときにデバッガに侵入している場合、このソリューションは正常に動作しますが、別の場所で例外をキャッチしてログに記録するだけではそれほど役に立ちません。

コード(immutable collections NuGet libraryに依存します):

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 package (described on my blog)をリリースしました。だから、良いトレースを得ることはもっと簡単になるはずです。

+0

ありがとうございました。私はそれがどのように動作するか試してみます:-)。私は何とか 'Paralell Stack'のような解決策がもっとあると期待していました。しかし、あなたはすべてを持つことはできません;-)。私は 'MyStack.Push()'ログだけを修正して、私がどこにいたのか知​​りたいのならどこでも必要ですか? – Patrick

+0

'MyStack.Push'と' MyStack.Pop'(処分)はスタックを変更します。はい、どこにでも追加する必要があります。 :(VS2012は「async」をサポートする最初のリリースです;将来的にはより良いデバッグサポートを得ることができます) –

+0

あなたは本当のところから来たものを知っているので、デバッグに違いがあります^^。あなたのブログがいいから時間を見つけた時に読んでくれる便利なエントリーがあるので最適化したいと思うかもしれません。 。 – Patrick

関連する問題