代码之家  ›  专栏  ›  技术社区  ›  Emad

应避免在已知情况下尝试捕捉

  •  2
  • Emad  · 技术社区  · 8 年前

    我有一个案子,我知道会发生,但非常罕见。例如,代码每运行10000次,这种情况就可能发生一次。

    我可以通过一个简单的 if 但是这个 如果 将运行多次而没有任何用处。

    另一方面,我可以将代码放在try-catch块中,当这种特殊情况发生时,我会执行恢复所需的操作。

    问题是哪一个更好?我知道,一般来说,由于开销问题,try-catch不应用于已知情况,并且应用程序逻辑不应依赖于catch代码,但多次运行if会产生更多的性能问题。我使用以下小测试代码对此进行了测试:

    static void Main(string[] args)
    {
        Stopwatch sc = new Stopwatch();
        var list = new List<int>();
        var rnd = new Random();
        for (int i = 0; i < 100000000; i++)
        {
            list.Add(rnd.Next());
        }
    
        sc.Start();
        DoWithIf(list);
        sc.Stop();
        Console.WriteLine($"Done with IFs in {sc.ElapsedMilliseconds} milliseconds");
        sc.Restart();
        DoWithTryCatch(list);
        sc.Stop();
        Console.WriteLine($"Done with TRY-CATCH in {sc.ElapsedMilliseconds} milliseconds");
        Console.ReadKey();
    }
    
    private static int[] DoWithTryCatch(List<int> list)
    {
        var res = new int[list.Count ];
        try
        {
            for (int i = 0; i < list.Count; i++)
            {
                res[i] = list[i];
            }
            return res;
        }
        catch
        {
            return res;
        }
    }
    
    private static int[] DoWithIf(List<int> list)
    {
        var res = new int[list.Count - 1];
        for (int i = 0; i < list.Count; i++)
        {
            if (i < res.Length)
                res[i] = list[i];
        }
        return res;
    }
    

    这段代码只是将大量数字复制到一个大小不够的数组中。在我的机器中,每次都需要检查数组边界 210毫秒 在使用try-catch的同时跑步,一旦跑了一圈就会碰到catch 190毫秒 .

    此外,如果你认为这取决于情况,我的情况是,我在应用程序中得到推送通知,并会检查我是否有消息的主题。如果没有,我将获取并存储主题信息,以供下一条消息使用。在几个主题中有许多消息。

    2 回复  |  直到 8 年前
        1
  •  3
  •   Zohar Peled    8 年前

    所以,准确地说,在你的测试中 if 选项比 try...catch 选项延迟20毫秒,循环次数为100000000次。
    也就是20/100000000,这就是 每次迭代0.0000002毫秒 .

    你真的认为这种纳米优化值得编写违背适当设计标准的代码吗?

    例外是指例外情况,即您无法控制或无法提前测试的事情,例如,当您从数据库读取数据时,连接在中间终止,诸如此类。 对可以用简单代码轻松测试的东西使用异常——好吧,这完全是错误的。

    例如,如果您已经证明这两个选项之间存在有意义的性能差异,那么也许您可以证明使用 尝试接住 而不是 -但这里显然不是这样。

    因此,总结一下-使用 如果 尝试接住 .

    你应该设计清晰的代码,而不是性能。
    编写代码,以尽可能清晰的方式表达它正在实现的算法。
    设定性能目标并对照它们衡量代码的性能。
    如果您的代码没有达到您的性能目标,请找出瓶颈并加以解决。
    在设计代码时,不要把时间浪费在纳米优化上。

        2
  •  2
  •   nvoigt    8 年前

    在您的情况下,您不知何故错过了明显的优化:如果您担心调用 if 10万次太多了。。。 ?

    private static int[] DoWithIf(List<int> list)
    {
        var res = new int[list.Count - 1];
    
        var bounds = Math.Min(res.Length, list.Count)
    
        for (int i = 0; i < bounds; i++)
        {        
            res[i] = list[i];
        }
        return res;
    }
    

    所以我知道这只是一个测试用例,但答案是:如果你需要它,优化你需要的。如果你在一个循环中有一些被认为是昂贵的东西,那么试着把它移出循环。 基于逻辑优化 ,而不是基于编译器构造。如果要优化编译器结构,无论如何都不应该使用托管和/或高级语言进行编码。