簡體   English   中英

調試異步/等待(調用堆棧)中的異常

[英]Debugging exceptions in a Async/Await (Call Stack)

我使用Async / Await釋放我的UI-Thread並完成多線程。 我遇到異常時遇到問題。 我的Async部件的Call Stack總是從ThreadPoolWorkQue.Dipatch()開始,這對我沒什么幫助。

我找到了MSDN文章Andrew Stasyuk。 Async Causality Chain跟蹤它,但據我了解,它不是一個隨時可用的解決方案。

如果在Async / Await中使用多線程,最好/最簡單的調試方法是什么?

您找到的文章很好地解釋了為什么調用堆棧不像我們大多數人認為的那樣工作。 從技術上講,調用堆棧只告訴我們在當前方法之后代碼返回的位置。 換句話說,調用堆棧是“代碼進行的地方”,而不是“代碼來自哪里”。

有趣的是,文章確實提到了一個解決方案,但沒有對其進行闡述。 我有一篇博文,詳細解釋了CallContext解決方案 實質上,您使用邏輯調用上下文來創建自己的“診斷上下文”。

我喜歡CallContext解決方案比文章中提供的解決方案更好,因為它確實可以工作所有形式的async代碼(包括像Task.WhenAll這樣的fork / join代碼)。

這是我所知道的最佳解決方案(除了做一些非常復雜的事情,比如掛鈎到分析API)。 CallContext方法的注意事項:

  • 它僅適用於.NET 4.5完整版。 不支持Windows應用商店應用,.NET 4.0等。
  • 您必須手動“檢測”您的代碼。 AFAIK無法自動注入它。
  • 異常不會自動捕獲邏輯調用上下文。 因此,如果您在拋出異常時進入調試器,此解決方案可以正常工作,但如果您只是在其他位置捕獲異常並記錄它們,那么它就不那么有用了。

代碼(取決於不可變集合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"
    {
        ...
    }
}

更新:我發布了一個NuGet包(在我的博客上描述) ,它使用PostSharp自動注入推送和彈出。 因此,獲得良好的痕跡現在應該更加簡單。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM