繁体   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