东莞seo建站优化工具,企业用酒解决方案,wordpress 口碑营销主题,关于军队建设网站. NET Core 2.1 现在具有可读的异步堆栈信息#xff01;使得异步、迭代器和字典 ( key not found ) 中的堆栈更容易追踪#xff01;这个大胆的主张意味着什么#xff1f;要知道#xff0c;为了确定调用 异步 和 迭代器方法的实际重载#xff0c;#xff08;这在以前… . NET Core 2.1 现在具有可读的异步堆栈信息使得异步、迭代器和字典 ( key not found ) 中的堆栈更容易追踪这个大胆的主张意味着什么要知道为了确定调用 异步 和 迭代器方法的实际重载这在以前从堆栈信息中跟踪几乎是不可能的System.Collections.Generic.KeyNotFoundException: The given key 0 was not present in the dictionary.at System.Collections.Generic.Dictionary2.get_Item(TKey key)at Program.Sequence(Int32 start)MoveNext()at Program.Sequence(Int32 start, Int32 end)MoveNext()at Program.MethodAsync()at Program.MethodAsync(Int32 v0)at Program.MethodAsync(Int32 v0, Int32 v1)at Program.MethodAsync(Int32 v0, Int32 v1, Int32 v2)at Program.MethodAsync(Int32 v0, Int32 v1, Int32 v2, Int32 v3)at Program.Main(String[] args)问题: “使堆栈信息可读”David Kean(davkean) 于 2017 年 10 月 13 日在dotnet/corefx#24627 提出 使堆栈信息可读 的问题:如今在 任务 (Task)、异步 (async) 和 等待 (await) 中普遍存在堆栈难以阅读的现象对于在 .NET 中输出异步的可阅读堆栈信息已经梦魂萦绕了5年...我直到 2017 年 10 月才意识到这个问题好在 .NET Core 现在是完全开源的所以我可以改变它。作为参考请参阅文章底部的代码它将会输出如下的异常堆栈System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary. at System.ThrowHelper.ThrowKeyNotFoundException() at System.Collections.Generic.Dictionary2.get_Item(TKey key) at Program.Sequenced__8.MoveNext() at Program.Sequenced__7.MoveNext() at Program.MethodAsyncd__6.MoveNext()--- End of stack trace from previous location where exception was thrown ---at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Program.MethodAsyncd__5.MoveNext()--- End of stack trace from previous location where exception was thrown ---at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Program.MethodAsyncd__4.MoveNext()--- End of stack trace from previous location where exception was thrown ---at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Program.MethodAsyncd__3.MoveNext()--- End of stack trace from previous location where exception was thrown ---at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Program.MethodAsyncd__2.MoveNext()--- End of stack trace from previous location where exception was thrown ---at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Program.Maind__1.MoveNext()为简洁起见删除了行号如 in C:\Work\Exceptions\Program.cs:line 14有时甚至可见更详细的胶水信息 at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task) at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
跟踪堆栈的一般用途是确定在源代码中发生错误的位置以及对应的路径。然而现如今我们无法避免异步堆栈同时还要面对很多无用的噪声干扰。PR: “隐藏请求中的异常堆栈帧 ”堆栈信息通常是从抛出异常的地方直接输出的。当异步函数抛出异常时它会执行一些额外的步骤来确保响应并且在延续执行既定方法之前会进行清理。当这些额外的步骤被添加到调用堆栈中时它们不会对我们确定堆栈信息有任何帮助因为它们实际上是在出现异常 之后 执行。所以它们是非常嘈杂和重复的对于确定代码在哪里出现异常上并没有任何额外的价值。实际产生的调用堆栈和输出的不一致:在删除这些异常堆栈帧后隐藏请求中的异常堆栈帧 dotnet/coreclr#14652 跟踪堆栈开始变得平易近人System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.at System.Collections.Generic.Dictionary2.get_Item(TKey key)at Program.Sequenced__7.MoveNext()at Program.Sequenced__6.MoveNext()at Program.MethodAsyncd__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---at Program.MethodAsyncd__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---at Program.MethodAsyncd__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---at Program.MethodAsyncd__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---at Program.MethodAsyncd__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---at Program.Maind__0.MoveNext()并且输出的调用堆栈与实际的调用堆栈一致: PR: “删除异步的 Edi 边界”异步中的异常使用 ExceptionDispatchInfo 类传播这意味着着在每个连接点都会有这样的边界信息--- End of stack trace from previous location where exception was thrown ---这只是让你知道两部分调用堆栈已经合并并且有个过渡。它如此频繁地出现在异步中增加了很多噪音并没有任何附加价值。在 删除异步的 Edi 边界 dotnet/coreclr#15781 后 所有的 堆栈信息变得有价值System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.at System.Collections.Generic.Dictionary2.get_Item(TKey key)at Program.Sequenced__7.MoveNext()at Program.Sequenced__6.MoveNext()at Program.MethodAsyncd__5.MoveNext()at Program.MethodAsyncd__4.MoveNext()at Program.MethodAsyncd__3.MoveNext()at Program.MethodAsyncd__2.MoveNext()at Program.MethodAsyncd__1.MoveNext()at Program.Maind__0.MoveNext()PR: “处理迭代器和异步方法中的堆栈”在上一节中堆栈已经是干净了但是要确定是什么情况还是很困难的一件事。堆栈中包含着由 C# 编译器创建的异步状态机的基础方法签名而不仅仅是你的源代码产生的。你可以确定方法的名称但是如果不深入挖掘则无法确定所调用的实际重载。在 处理迭代器和异步方法中的堆栈 dotnet/coreclr#14655 之后堆栈更接近原始来源System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.at System.Collections.Generic.Dictionary2.get_Item(TKey key)at Program.Sequence(Int32 start)MoveNext()at Program.Sequence(Int32 start, Int32 end)MoveNext()at Program.MethodAsync()at Program.MethodAsync(Int32 v0)at Program.MethodAsync(Int32 v0, Int32 v1)at Program.MethodAsync(Int32 v0, Int32 v1, Int32 v2)at Program.MethodAsync(Int32 v0, Int32 v1, Int32 v2, Int32 v3)at Program.Main(String[] args)PR: “实现 KeyNotFoundException 的堆栈追踪”因为有额外的奖励我着手实现抛出 “ KeyNotFoundException ” 的堆栈追踪。Anirudh Agnihotry (Anipik) 提出了 实现 KeyNotFoundException 的堆栈追踪dotnet/coreclr#15201这意味着这个异常现在要告诉你哪个 key 找不到的信息System.Collections.Generic.KeyNotFoundException: The given key 0 was not present in the dictionary.at System.Collections.Generic.Dictionary2.get_Item(TKey key)at Program.Sequence(Int32 start)MoveNext()at Program.Sequence(Int32 start, Int32 end)MoveNext()at Program.MethodAsync()at Program.MethodAsync(Int32 v0)at Program.MethodAsync(Int32 v0, Int32 v1)at Program.MethodAsync(Int32 v0, Int32 v1, Int32 v2)at Program.MethodAsync(Int32 v0, Int32 v1, Int32 v2, Int32 v3)at Program.Main(String[] args)支持的运行时以及相关进展这些改进将在稍晚的时间发布到 Mono 上并在下一个阶段发布。但是如果您使用的是较早的运行时版本 (.NET Core 1.0 - 2.0; .NET Framework 或 Mono) 想要获得一样的效果需要使用 Ben.Demystifier 提供的Nuget 包并且在你的异常中使用 .Demystify() 的方法:catch (Exception e)
{Console.WriteLine(e.Demystify());
}这些改进将会产生与 C相得映彰的输出信息最令人高兴的还是全都会被内置System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.at TValue System.Collections.Generic.DictionaryTKey, TValue.get_Item(TKey key)at IEnumerableint Program.Sequence(int start)MoveNext()at IEnumerableint Program.Sequence(int start, int end)MoveNext()at async Taskint Program.MethodAsync()at async Taskint Program.MethodAsync(int v0)at async Taskint Program.MethodAsync(int v0, int v1)at async Taskint Program.MethodAsync(int v0, int v1, int v2)at async Taskint Program.MethodAsync(int v0, int v1, int v2, int v3)at async Task Program.Main(string[] args).NET Core 2.1 将成为 .NET Core 的最佳版本原因说不完这只是变得更美好的一小步...上面提到的触发异常的代码及对应的堆栈信息class Program{ static Dictionaryint, int _dict new Dictionaryint, int(); static async Task Main(string[] args) { try{ var value await MethodAsync(1, 2, 3, 4);Console.WriteLine(value);} catch (Exception e){Console.WriteLine(e);}} static async Taskint MethodAsync(int v0, int v1, int v2, int v3) await MethodAsync(v0, v1, v2); static async Taskint MethodAsync(int v0, int v1, int v2) await MethodAsync(v0, v1); static async Taskint MethodAsync(int v0, int v1) await MethodAsync(v0); static async Taskint MethodAsync(int v0) await MethodAsync(); static async Taskint MethodAsync() { await Task.Delay(1000); int value 0; foreach (var i in Sequence(0, 5)) { value i;} return value;} static IEnumerableint Sequence(int start, int end) { for (var i start; i end; i){ foreach (var item in Sequence(i)) { yield return item;}}} static IEnumerableint Sequence(int start) { var end start 10; for (var i start; i end; i){_dict[i] _dict[i] 1; // Throws exceptionyield return i;}}
}原文地址https://www.cnblogs.com/chenug/p/8401356.html.NET社区新闻深度好文欢迎访问公众号文章汇总 http://www.csharpkit.com