try catch 的开销

一:背景

1. 讲故事

在项目中摸爬滚打几年,应该或多或少的见过有人把异常当做业务逻辑处理的情况(┬_┬),比如说判断一个数字是否为整数,就想当然的用try catch包起来,再进行 int.Parse,如果抛异常就说明不是整数,简单粗暴,也不需要写正则或者其他逻辑,再比如一个字符串强制转化为Enum,直接用Enum.Parse,可能是因为对异常的开销不是特别了解,这种不好的使用习惯也许被官方发现了,后续给我们补了很多的Try前缀的方法,比如:int.TryParse , Enum.TryParsedict.TryGetValue ,用代码展示如下:

            //原始写法
            var num = int.Parse("1");

            //使用try方式
            var result = 0;
            var b = int.TryParse("1", out result);

用Try系列方法没毛病,但这写法让人吐槽,还要单独定义result变量,没撤,官方还得靠我们这些开发者给他们发扬光大😄😄😄,终于在C# 7.0 中新增了一个 out variables 语法糖。


            //try out 变量模式
            var c = int.TryParse("1", out int result2);

这种 out 变量 模式就🐮👃了,一个方法获取两个值,还没有抛异常的风险。

二:为什么要用tryxxx方法

有了tryxxx方法之后,你就应该明白微软已经在提醒我们开发人员不要滥用异常,尤其在可预知可预见的场景下,毕竟他们知道异常的开销真的是太大了,不知者不怪哈。

1. 肉眼看得见的低性能

为了让大家肉眼能看见,我们就用异常方法和tryxxx方法做一个性能比较,迭代50w次,看看各自的性能如何?


            for (int i = 0; i < 3; i++)
            {
                var watch = Stopwatch.StartNew();
                for (int k = 0; k < 50000; k++)
                {
                    try
                    {
                        var num = int.Parse("xxx");
                    }
                    catch (Exception ex) { }
                }
                watch.Stop();

                Console.WriteLine($"i={i + 1},耗费:{watch.ElapsedMilliseconds}");
            }
            Console.WriteLine("---------------------------------------------");
            for (int i = 0; i < 3; i++)
            {
                var watch = Stopwatch.StartNew();

                for (int k = 0; k < 50000; k++)
                {
                   var num = int.TryParse("xxx", out int reuslt);
                }

                watch.Stop();

                Console.WriteLine($"i={i + 1},耗费:{watch.ElapsedMilliseconds}");
            }
            Console.ReadLine();

看结果还挺吓人的,相差480倍, 

posted @ 2020-08-11 14:03  有度科技  阅读(651)  评论(0)    收藏  举报