【电力vr源码】【源码精灵2019】【安逸付源码】catch 源码

时间:2024-11-25 04:57:07 来源:扑克分析源码 分类:知识

1.七爪源码:像专业人士一样在 Node.js 中处理错误
2.C++如何使用try-catch
3.Golang源码剖析panic与recover,看不懂你打我好了
4.为什么不建议用 try catch

catch 源码

七爪源码:像专业人士一样在 Node.js 中处理错误

       处理错误是构建生产级应用的关键。本文将指导你如何像专业人士一样在 Node.js 中处理错误。

       错误并非都相同。了解不同类型的错误有助于你对它们进行分类和处理。首先,电力vr源码了解所有可能的错误情况,然后学会轻松应对它们。

       处理未找到的 URL 错误。当遇到用户试图访问不存在的 URL,如 /user 而非 /users,需要通知用户。在 ExpressJS 中,只需在所有路由之后添加特殊中间件,即可捕获所有未匹配的路由并返回正确的错误响应。

       使用特殊中间件处理所有错误。在 Express 中,有一个特定的中间件负责处理所有错误,确保它放置在所有其他中间件和路由定义之后。将此中间件添加到索引文件,确保所有错误均被处理。

       自定义错误对象。默认的错误对象在抛出错误时提供有限信息。可以创建一个自定义错误类,添加更多属性,源码精灵2019并区分各种错误对象。这有助于提高错误处理的精确度。

       在路由内部处理错误。抛出自定义错误,实现错误处理的灵活性和控制性。利用错误对象调用下一个函数,提高代码的可维护性和整洁性。

       创建自定义包装函数。捕获所有错误,并从中心位置调用下一个函数,消除 try/catch 块的使用,简化代码结构。

       微调错误处理。根据需求定制错误类,例如创建一个处理未找到的路由的新错误类,简化错误处理流程,添加有意义的状态码,让代码更具可读性和功能。

       优雅处理程序员错误。遇到未处理的承诺拒绝等错误时,优雅地重启应用,以避免出现不可预料的问题。使用错误中间件集中处理错误,遵循单一责任原则,安逸付源码分离关注点。

       最后,通过实践,你将能更熟练地处理 Node.js 中的错误,构建更稳定、更安全的应用程序。不断学习和实践,你的编程技能将得到显著提升。愿你在编程之旅中取得更多成就。

C++如何使用try-catch

       /// 资源数   public static int resourceNumber;   /// 进程数   public static int processNumber;   /// 可用资源数组   public static int[] Available;   /// 工作向量   public static int[] work;   /// 它表示系统是否有足够的资源分配给进程   public static bool[] Finish;   /// 最大需求矩阵   public static int[][] Max;   /// 分配矩阵   public static int[][] Allocation;   /// 需求矩阵   public static int[][] Need;   /// 安全序列   public static int[] SafeSequence;   /// 资源请求向量   public static int[] Request;   算法思想:   主要是:递归+深度优先搜寻+回溯   算法源代码如下:   /// 深搜+回溯实现银行家算法   /// <param name="n">已完成的进程数</param>   public void DFS_searchSafeSequence(int n)   {   if (n == processNumber)   {   //找到一个安全序列,可以显示所有安全序列   //显示在richTextBoxshow.Text上   for (int i = 0; i < processNumber; i++)   {   richTextBoxshow.Text += SafeSequence[i] + " ";   }   richTextBoxshow.Text += "\n";   return;   }   for (int i = 0; i < processNumber; i++)   {   if (Finish[i] == false)//进程尚未完成   {   //判断现有资源是否可以满足这个进程   bool isOK = true;   for (int j = 0; j < resourceNumber; j++)   {   if (Need[i][j] > work[j])   {   isOK = false;   break;   }   }   //可以满足   if (isOK)   {   //先试探的将资源分配给这个进程   for (int j = 0; j < resourceNumber; j++)   {   work[j] += Allocation[i][j];   }   //已经完成   Finish[i] = true;   //加入安全序列   SafeSequence[n] = i;   //继续搜索   DFS_searchSafeSequence(n+1);   //回溯   Finish[i] = false;   SafeSequence[n] = -1;   for (int j = 0; j < resourceNumber; j++)   {   work[j] -= Allocation[i][j];   }   }   }   }   }

Golang源码剖析panic与recover,看不懂你打我好了

       哈喽,大家好,我是asong,今天与大家来聊一聊go语言中的"throw、try.....catch{ }"。如果你之前是一名java程序员,我相信你一定吐槽过go语言错误处理方式,但是这篇文章不是来讨论好坏的,我们本文的重点是带着大家看一看panic与recover是如何实现的。上一文我们讲解了defer是如何实现的,但是没有讲解与defer紧密相连的recover,想搞懂panic与recover的实现也没那么简单,就放到这一篇来讲解了。废话不多说,githud的源码直接开整。

       Go 语言中panic 关键字主要用于主动抛出异常,类似 java 等语言中的 throw 关键字。panic 能够改变程序的控制流,调用 panic 后会立刻停止执行当前函数的剩余代码,并在当前 Goroutine 中递归执行调用方的 defer;

       Go 语言中recover 关键字主要用于捕获异常,让程序回到正常状态,类似 java 等语言中的 try ... catch 。recover 可以中止 panic 造成的程序崩溃。它是一个只能在 defer 中发挥作用的函数,在其他作用域中调用不会发挥作用;

       recover只能在defer中使用这个在标准库的注释中已经写明白了,我们可以看一下:

       这里有一个要注意的点就是recover必须要要在defer函数中使用,否则无法阻止panic。最好的验证方法是先写两个例子:

       运行我们会发现example2()方法的panic是没有被recover住的,导致整个程序直接crash了。这里大家肯定会有疑问,为什么直接写recover()就不能阻止panic了呢。我们在 详解defer实现机制(附上三道面试题,我不信你们都能做对)讲解了defer实现原理,一个重要的知识点**defer将语句放入到栈中时,也会将相关的值拷贝同时入栈。**所以defer recover()这种写法在放入defer栈中时就已经被执行过了,panic是发生在之后,所以根本无法阻止住panic。optional指标源码

       通过运行结果可以看出panic不会影响defer函数的使用,所以他是安全的。

       这里我开了两个协程,一个协程会发生panic,导致程序崩溃,但是只会执行自己所在Goroutine的延迟函数,所以正好验证了多个 Goroutine 之间没有太多的关联,一个 Goroutine 在 panic 时也不应该执行其他 Goroutine 的延迟函数。

       其实我们在实际项目开发中,经常会遇到panic问题, Go 的 runtime 代码中很多地方都调用了 panic 函数,对于不了解 Go 底层实现的新人来说,这无疑是挖了一堆深坑。我们在实际生产环境中总会出现panic,但是我们的程序仍能正常运行,这是因为我们的框架已经做了recover,他已经为我们兜住底,比如gin,我们看一看他是怎么做的。

       我们先来写个简单的代码,看看他的汇编调用:执行go tool compile -N -l -S main.go就可以看到对应的汇编码了,我们截取部分片段分析:

       上面重点部分就是画红线的三处,第一步调用runtime.deferprocStack创建defer对象,这一步大家可能会有疑惑,我上一文忘记讲个这个了,这里先简单概括一下,defer总共有三种模型,编译一个函数里只会有一种defer模式。在讲defer实现机制时,我们一起看过defer的结构,其中有一个字段就是_panic,是触发defer的作用,我们来看看的panic的结构:

       简单介绍一下上面的字段:

       上面的pc、sp、goexit我们单独讲一下,runtime包中有一个Goexit方法,Goext能够终止调用它的goroutine,其他的goroutine是不受影响的,goexit也会在终止goroutine之前运行所有延迟调用函数,Goexit不是一个panic,所以这些延迟函数中的任何recover调用都将返回nil。如果我们在主函数中调用了Goexit会终止该goroutine但不会返回func main。由于func main没有返回,因此程序将继续执行其他gorountine,直到所有其他goroutine退出,程序才会crash。

       下面就开始我们的重点吧~。

       在讲defer实现机制时,我们一起看过defer的结构,其中有一个字段就是_panic,是触发defer的作用,我们来看看的panic的结构:简单介绍一下上面的字段:上面的pc、sp、goexit我们单独讲一下,runtime包中有一个Goexit方法,Goext能够终止调用它的goroutine,其他的goroutine是不受影响的,goexit也会在终止goroutine之前运行所有延迟调用函数,Goexit不是一个panic,所以这些延迟函数中的任何recover调用都将返回nil。如果我们在主函数中调用了Goexit会终止该goroutine但不会返回func main。由于func main没有返回,因此程序将继续执行其他gorountine,直到所有其他goroutine退出,程序才会crash。写个简单的例子:运行上面的例子你就会发现,即使在主goroutine中调用了runtime.Goexit,其他goroutine是没有任何影响的。所以结构中的pc、sp、goexit三个字段都是为了修复runtime.Goexit,这三个字段就是为了保证该函数的一定会生效,因为如果在defer中发生panic,那么goexit函数就会被取消,所以才有了这三个字段做保护。看这个例子:

       英语好的可以看一看这个: github.com/golang/go/is...,这就是上面的一个例子,这里就不过多解释了,了解就好。

       接下来我们再来看一看gopanic方法。

       gopanic的代码有点长,我们一点一点来分析:

       根据不同的类型判断当前发生panic错误,这里没什么多说的,接着往下看。

       上面的代码都是截段,这些部分都是为了判断当前defer是否可以使用开发编码模式,具体怎么操作的就不展开了。

       在第三部分进行defer内联优化选择时会执行调用延迟函数(reflectcall就是这个作用),也就是会调用runtime.gorecover把recoverd = true,具体这个函数的操作留在下面讲,因为runtime.gorecover函数并不包含恢复程序的逻辑,程序的恢复是在gopanic中执行的。先看一下代码:

       这段代码有点长,主要就是分为两部分:

       第一部分主要是这个判断if gp._panic != nil && gp._panic.goexit && gp._panic.aborted { ... },正常recover是会绕过Goexit的,所以为了解决这个,添加了这个判断,这样就可以保证Goexit也会被recover住,这里是通过从runtime._panic中取出了程序计数器pc和栈指针sp并且调用runtime.recovery函数触发goroutine的调度,调度之前会准备好 sp、pc 以及函数的返回值。

       第二部分主要是做panic的recover,这也与上面的流程基本差不多,他是从runtime._defer中取出了程序计数器pc和栈指针sp并调用recovery函数触发Goroutine,跳转到recovery函数是通过runtime.call进行的,我们看一下其源码(src/runtime/asm_amd.s 行):

       因为go语言中的runtime环境是有自己的堆栈和goroutine,recovery函数也是在runtime环境执行的,所以要调度到m->g0来执行recovery函数,我们在看一下recovery函数:

       在recovery 函数中,利用 g 中的两个状态码回溯栈指针 sp 并恢复程序计数器 pc 到调度器中,并调用 gogo 重新调度 g , goroutine 继续执行,recovery在调度过程中会将函数的返回值设置为1。这个有什么作用呢? 在deferproc函数中找到了答案:

       当延迟函数中recover了一个panic时,就会返回1,当 runtime.deferproc 函数的返回值是 1 时,编译器生成的代码会直接跳转到调用方函数返回之前并执行 runtime.deferreturn,跳转到runtime.deferturn函数之后,程序就已经从panic恢复了正常的逻辑。

       在这里runtime.fatalpanic实现了无法被恢复的程序崩溃,它在中止程序之前会通过 runtime.printpanics 打印出全部的 panic 消息以及调用时传入的参数。

       这就是这个逻辑流程,累死我了。。。。

       结尾给大家发一个小福利,哈哈,这个福利就是如果避免出现panic,要注意这些:这几个是比较典型的,还有很多会发生panic的地方,交给你们自行学习吧~。

       好啦,这篇文章就到这里啦,素质三连(分享、点赞、在看)都是笔者持续创作更多优质内容的动力!

为什么不建议用 try catch

       ä¸åŒè¯­è¨€å¤„理Try Catch的机制不一样,所以也会有不同回答。

       æ¯”如C++,是不推荐用try catch的,它推荐使用Windows API那种HResult来返回错误情况,原因是try catch会在已有的代码上面增加额外的cost, 这个额外的cost不是说只有throw exception的时候才会有,而是在try catch block里面的每一行代码中都会有,这也是为什么他不建议你使用try catch最主要的原因。在Windows的源代码中,是没有任何try catch的,全部用HResult来处理。

       æ¯”如C#, try catch是建议使用的,C#设计的时候吸取的C++ try catch的教训,所以直接用Try catch包裹已有代码增加的cost可以忽略不计,但是如果真的在代码运行过程中throw exception了,这个cost还是很大的。所以,在C#代码设计中,throw exception基本上是你认为不会发生这种意外的情况下,否则,如果是常见错误,最好不要throw exception。

       æ¯”如Java, try catch也是建议使用的,我这个用的不熟,不过看它的说明,即使是throw exception的时候的cost也很小。

       æ€»ç»“说来,try catch是否建议使用要看具体语言,最重要衡量的标准就是它对已有的代码性能有多大的影响。但是从它设计的角度就是为了处理一些意料不到的情况,但是因为当初引入的时候各种各样的原因,导致有些语言为了性能,不推荐使用。

       BTW, try catch最好不要catch (Exception), 这样会吃掉不该吃的问题,比如C#中的StackOverflowException, OutOfMemoryException, NullReferenceException etc. 该crash的时候就应该让App crash, restart, 这也是保护你service的一个好方法。

       å¸Œæœ›å¯¹ä½ æœ‰å¸®åŠ©~