.NET Core 2.1中改进的堆栈信息

. 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.Dictionary`2.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.Dictionary`2.get_Item(TKey key)   at Program.<Sequence>d__8.MoveNext()   at Program.<Sequence>d__7.MoveNext()   at Program.<MethodAsync>d__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.<MethodAsync>d__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.<MethodAsync>d__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.<MethodAsync>d__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.<MethodAsync>d__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.<Main>d__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.Dictionary`2.get_Item(TKey key)at Program.<Sequence>d__7.MoveNext()at Program.<Sequence>d__6.MoveNext()at Program.<MethodAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---at Program.<MethodAsync>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---at Program.<MethodAsync>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---at Program.<MethodAsync>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---at Program.<MethodAsync>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---at Program.<Main>d__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.Dictionary`2.get_Item(TKey key)at Program.<Sequence>d__7.MoveNext()at Program.<Sequence>d__6.MoveNext()at Program.<MethodAsync>d__5.MoveNext()at Program.<MethodAsync>d__4.MoveNext()at Program.<MethodAsync>d__3.MoveNext()at Program.<MethodAsync>d__2.MoveNext()at Program.<MethodAsync>d__1.MoveNext()at Program.<Main>d__0.MoveNext()

PR: “处理迭代器和异步方法中的堆栈”

在上一节中,堆栈已经是干净了,但是要确定是什么情况,还是很困难的一件事。

堆栈中包含着由 C# 编译器创建的异步状态机的基础方法签名,而不仅仅是(你的)源代码产生的。

你可以确定方法的名称,但是如果不深入挖掘,则无法确定所调用的实际重载。

在 处理迭代器和异步方法中的堆栈 dotnet/coreclr#14655 之后,堆栈更接近原始来源:

System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.at System.Collections.Generic.Dictionary`2.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.Dictionary`2.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.Dictionary<TKey, TValue>.get_Item(TKey key)at IEnumerable<int> Program.Sequence(int start)+MoveNext()at IEnumerable<int> Program.Sequence(int start, int end)+MoveNext()at async Task<int> Program.MethodAsync()at async Task<int> Program.MethodAsync(int v0)at async Task<int> Program.MethodAsync(int v0, int v1)at async Task<int> Program.MethodAsync(int v0, int v1, int v2)at async Task<int> 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 Dictionary<int, int> _dict = new Dictionary<int, 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 Task<int> MethodAsync(int v0, int v1, int v2, int v3)    
   
=> await MethodAsync(v0, v1, v2);  
  static async Task<int> MethodAsync(int v0, int v1, int v2)  
     
=> await MethodAsync(v0, v1);  
   static async Task<int> MethodAsync(int v0, int v1)      
 
=> await MethodAsync(v0);    
   static async Task<int> MethodAsync(int v0)    
   
=> await MethodAsync();  
   static async Task<int> MethodAsync()    {      
     await Task.Delay(1000);      
      int value = 0;      
    foreach (var i in Sequence(0, 5))        {      
         value += i;}        return value;}  
   
    static IEnumerable<int> Sequence(int start, int end)    {    
       for (var i = start; i <= end; i++){          
         foreach (var item in Sequence(i))            {  
                      yield return item;}}}  
    static IEnumerable<int> 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/322199.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

jzoj3362,bzoj3758-[NOI2013模拟]数数【分段打表,背包,状压】

正题 bzojbzojbzoj题面链接:https://www.lydsy.com/JudgeOnline/problem.php?id3758 题目大意 求A∼BA\sim BA∼B中有多少个数满足数字上的位数可以分成两个和相等的集合。 解题思路 首先我们考虑如何快速判断一个数是否是满足要求的数&#xff0c;我们可以用背包&#xff0…

Nacos(八)之Docker

转载自 Nacos Docker 快速开始 操作步骤 Clone 项目 git clone https://github.com/nacos-group/nacos-docker.git cd nacos-docker单机模式 Derby docker-compose -f example/standalone-derby.yaml up单机模式 MySQL 如果希望使用MySQL5.7 docker-compose -f example/sta…

微软高管解读财报:努力创新云基础架构

2月1日&#xff0c;微软发布了该公司截至2017年12月31日的2018年第二财季财报&#xff08;即2017年第四季度&#xff09;。财报显示&#xff0c;微软第二财季营收为289.18亿美元&#xff0c;比上年同期的258.26亿美元增长了12%。受税改与就业法案相关的一次性费用138亿美元的影…

欢乐纪中某A组赛【2019.7.12】

前言 暴力写挂垫底了呀\huge \color{red}\texttt{暴力写挂}\small\color{white}\\\texttt{垫底了呀}暴力写挂垫底了呀 %%%ZZYrank1\texttt{\%\%\% ZZY rank1}%%% ZZY rank1 成绩 JJJ表示初中&#xff0c;HHH表示高中后面加的是几年级 RankRankRankPersonPersonPersonScoreScore…

Nacos(九)之Dubbo 融合 Nacos 成为注册中心

转载自 Dubbo 融合 Nacos 成为注册中心 Nacos 作为 Dubbo 生态系统中重要的注册中心实现&#xff0c;本文将会介绍如何进行 Dubbo 对接 Nacos 注册中心的工作。 预备工作 请确保后台已经启动 Nacos 服务&#xff0c;可先行参考 Nacos 快速入门。 快速上手 Dubbo 融合 Nac…

在.NET Core中处理一个接口多个不同实现的依赖注入问题

前言近段时间在准备公司的技术分享&#xff0c;所以这段时间将大部分时间放在准备分享内容上去了。博客也就停了一下下。在.NET Core中处理依赖注入问题时&#xff0c;往往是定义好了一个操作规范的接口&#xff0c;会有N多个基于不同技术的实现&#xff0c;根据实际情况在项目…

P3085,jzoj3234-[USACO13OPEN]阴和阳【点分治】

正题 题目链接:https://www.luogu.org/problemnew/show/P3085 题目大意 一棵树只有−1-1−1和111的边权&#xff0c;询问有多少条路径可以找到一个分界点使得分出的两条路径长度为000。 解题思路 询问路径显然点分治一波。 然后考虑分界点的两种情况 分界点在当前扫描到的…

Nacos(十)之Kubernetes Nacos

转载自 Kubernetes Nacos 本项目包含一个可构建的Nacos Docker Image&#xff0c;旨在利用StatefulSets在Kubernetes上部署Nacos 快速开始 Clone 项目 git clone https://github.com/nacos-group/nacos-k8s.git简单例子如果你使用简单方式快速启动,请注意这是没有使用持久化…

.net core连接MongoDB

前两天在学习MongoDB相关的知识&#xff0c;做了个小Demo&#xff0c;做的是省份下面有多少所学校&#xff0c;嗯&#xff0c;做的比较粗暴。。。连接MongoDB首先要通过Nuget添加一个MongoDB的包&#xff0c;下载此包安装完毕后开始写代码了&#xff0c;创建一个省份实体&#…

P4139-上帝与集合的正确用法【欧拉定理】

正题 题目链接:https://www.luogu.org/problemnew/show/P4139 题目大意 求2222222...%p2^{2^{2^{2^{2^{2^{2^{...}}}}}}}\%p2222222...%p 解题思路 欧拉定理 ab{ab%φ(p)φ(p)(b>φ(p))ab%φ(p)(b≤φ(p))a^b\left\{\begin{matrix}a^{b\%\varphi(p)\varphi(p)}(b>\var…

Nacos(十一)之NacosSync 介绍

转载自 NacosSync 介绍 介绍 NacosSync是一个支持多种注册中心的同步组件,基于Spring boot开发框架,数据层采用Spring Data JPA,遵循了标准的JPA访问规范,支持多种数据源存储,默认使用Hibernate实现,更加方便的支持表的自动创建更新使用了高效的事件异步驱动模型, 支持多种自…

Ocelot 集成Butterfly 实现分布式跟踪

微服务&#xff0c;通常都是用复杂的、大规模分布式集群来实现的。微服务构建在不同的软件模块上&#xff0c;这些软件模块&#xff0c;有可能是由不同的团队开发、可能使用不同的编程语言来实现、有可能布在了几千台服务器&#xff0c;横跨多个不同的数据中心。因此&#xff0…

jzoj1213-棋盘上的士兵【状压dp】

正题 题目大意 一个骑士会攻击对角线的位置&#xff0c;然后n∗nn*nn∗n的棋盘上放mmm个骑士求方案数。 解题思路 我们将棋盘翻转以两个对角线为中间&#xff0c;这样骑士就变成了横着打和竖着打。 设fi,s,jf_{i,s,j}fi,s,j​表示第iii条对角线&#xff0c;不能放置骑士的位置…

Nacos(十二)之Java SDK

转载自 Java SDK 概述部分 Maven 坐标 <dependency> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-client</artifactId> <version>${version}</version> </dependency>配置管理 获取配置 描述 用于服务启动…

聊聊AspectCore动态代理中的拦截器(一)

前言在上一篇文章使用AspectCore动态代理中&#xff0c;简单说明了AspectCore.DynamicProxy的使用方式&#xff0c;由于介绍的比较浅显&#xff0c;也有不少同学留言询问拦截器的配置&#xff0c;那么在这篇文章中&#xff0c;我们来详细看一下AspectCore中的拦截器使用。两种配…

P5135-painting【组合数学】

正题 题目链接:https://www.luogu.org/problemnew/show/P5135 题目大意 n∗mn*mn∗m的矩阵每列恰好有一个黑格子&#xff0c;询问两个中一个 每列黑格子所在行数不下降每列黑格子所在行数单调上升 的方案数 解题思路 显然询问1答案就是Cnm−1mC_{nm-1}^mCnm−1m​(插板法) …

你可能不知道的.Net Core Configuration

执行原理1. 配置读取顺序&#xff1a;与代码先后顺序一致。public Startup(IHostingEnvironment env){var builder new ConfigurationBuilder().SetBasePath(env.ContentRootPath).AddJsonFile("appsettings.json", false, true).AddJsonFile("cussettings.jso…

Dubbo(一)之简介

转载自 Dubbo 2.7入门 一、背景 本文介绍了网站应用的演进 随着互联网的发展&#xff0c;网站应用的规模不断扩大&#xff0c;常规的垂直应用架构已无法应对&#xff0c;分布式服务架构以及流动计算架构势在必行&#xff0c;亟需一个治理系统确保架构有条不紊的演进。 单一…

P1600-天天爱跑步【LCA,桶,树上差分】

正题 题目链接:https://www.luogu.org/problemnew/show/P1600 题目大意 一棵nnn个点的树&#xff0c;通过每条边需要时间为1。有mmm个玩家从SiS_iSi​跑到TiT_iTi​&#xff08;不停留&#xff0c;跑完之后马上消失&#xff09;。然后对于第iii个点求第wiw_iwi​刻停留在改点…

Dubbo(二)之SpringBoot nacos集成

一、框架 使用springboot启动&#xff0c;注册中心现在naocs。 nacos安装 二、样例项目 &#xff08;1&#xff09;maven设置 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId> <…