C#中的例外有多贵?

Cha*_*nce 70 c# exception

C#中的例外有多贵?只要堆叠不深,它们似乎并不是非常昂贵; 但我读过相互矛盾的报道.

有没有被反驳的确定性报告?

Rob*_*son 67

Jon Skeet 于2006年1月在.NET中编写了Exceptions和Performance

哪个更新了Exceptions和Performance Redux(感谢@Gulzar)

Rico Mariani在.NET异常的真实成本中所说的 - 解决方案


另请参考:Krzysztof Cwalina - 设计指南更新:异常投掷


Hel*_*ein 17

在阅读了异常在性能方面代价高昂之后,我将一个简单的测量程序整合在一起,与Jon Skeet多年前发布的程序非常相似.我在这提到这里主要是为了提供更新的数字.

程序花费了29914毫秒来处理一百万个异常,相当于每毫秒33个异常.这足够快,使异常成为大多数情况下返回代码的可行替代方案.

但请注意,使用返回代码而不是异常,同一程序运行时间不到一毫秒,这意味着异常至少比返回代码慢30,000倍.正如Rico Mariani强调的那样,这些数字也是最小数字.在实践中,抛出和捕获异常将花费更多时间.

在具有英特尔酷睿2双核T8100 @ 2,1 GHz的笔记本电脑上测试,发布版本中的.NET 4.0 不能在调试器下运行(这会使速度变慢).

这是我的测试代码:

static void Main(string[] args)
{
    int iterations = 1000000;
    Console.WriteLine("Starting " + iterations.ToString() + " iterations...\n");

    var stopwatch = new Stopwatch();

    // Test exceptions
    stopwatch.Reset();
    stopwatch.Start();
    for (int i = 1; i <= iterations; i++)
    {
        try
        {
            TestExceptions();
        }
        catch (Exception)
        {
            // Do nothing
        }
    }
    stopwatch.Stop();
    Console.WriteLine("Exceptions: " + stopwatch.ElapsedMilliseconds.ToString() + " ms");

    // Test return codes
    stopwatch.Reset();
    stopwatch.Start();
    int retcode;
    for (int i = 1; i <= iterations; i++)
    {
        retcode = TestReturnCodes();
        if (retcode == 1)
        {
            // Do nothing
        }
    }
    stopwatch.Stop();
    Console.WriteLine("Return codes: " + stopwatch.ElapsedMilliseconds.ToString() + " ms");

    Console.WriteLine("\nFinished.");
    Console.ReadKey();
}

static void TestExceptions()
{
    throw new Exception("Failed");
}

static int TestReturnCodes()
{
    return 1;
}
Run Code Online (Sandbox Code Playgroud)

  • 作为 REST 调用返回值的返回机制怎么样?考虑到网络连接本身的开销,抛出嵌入 HTTP 状态代码的异常似乎是一种非常可靠、统一且相对便宜的返回值机制,更不用说有关请求出错位置的更多有用信息了。它还极大地简化了业务逻辑实现,因为您要么成功返回,要么抛出信息丰富的可记录异常。 (4认同)
  • “这足够快,足以使异常成为大多数情况下返回代码的可行替代方案。”我不会说深度为 2-3 的调用堆栈确实代表“_大多数情况_”。也许还应该考虑更深的调用堆栈。 (3认同)
  • 因此,正如我发现的那样,它们在紧密的游戏循环中*不*可行。我试图通过索引越界检查来偷懒:) (2认同)

Col*_*ett 16

我想我在营地,如果异常影响应用程序的性能,然后你扔WAY太多了.例外情况应该是特殊条件,而不是常规错误处理.

也就是说,我对如何处理异常的回忆基本上是在堆栈中找到一个与抛出的异常类型相匹配的catch语句.因此,性能将受到影响,因为您从捕获的深度以及您拥有的捕获语句数量.

  • 对我来说听起来不太好听.实际上听起来就像Jon Skeet所说的那样,"如果你遇到异常严重损害你的表现的问题,那么你在使用异常时就会遇到问题而不仅仅是表现." (17认同)
  • 如果陈述我的意见是"讲道",那么就这样吧.我的观点仍然表明,如果异常影响您的性能,那么您需要减少异常.这不是Chance的问题所在,但它肯定是主题.我怎么知道Chance已经考虑过我的观点了? (15认同)
  • @Colin虽然我同意你的陈述,但你的主题是迂回曲折,你的语气有点偏执. (3认同)

mpe*_*pen 5

就我而言,例外非常昂贵。我改写了这个:

public BlockTemplate this[int x,int y, int z]
{
    get
    {
        try
        {
            return Data.BlockTemplate[World[Center.X + x, Center.Y + y, Center.Z + z]];
        }
        catch(IndexOutOfRangeException e)
        {
            return Data.BlockTemplate[BlockType.Air];
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

进入这个:

public BlockTemplate this[int x,int y, int z]
{
    get
    {
        int ix = Center.X + x;
        int iy = Center.Y + y;
        int iz = Center.Z + z;
        if (ix < 0 || ix >= World.GetLength(0)
            || iy < 0 || iy >= World.GetLength(1)
            || iz < 0 || iz >= World.GetLength(2)) 
            return Data.BlockTemplate[BlockType.Air];
        return Data.BlockTemplate[World[ix, iy, iz]];
    }
}
Run Code Online (Sandbox Code Playgroud)

我注意到速度增加了大约 30 秒。该函数在启动时至少被调用 32,000 次。代码的意图不是很清楚,但节省的成本是巨大的。

  • 未处理的异常并不昂贵。 (4认同)

Ale*_*lex 5

我自己进行了测量,以了解异常影响的严重程度。我没有尝试测量抛出/捕获异常的绝对时间。我最感兴趣的是,如果在每次传递中抛出异常,循环会变慢多少。测量代码如下所示:

for(; ; ) {
   iValue = Level1(iValue);
   lCounter += 1;
   if(DateTime.Now >= sFinish)
       break;
}
Run Code Online (Sandbox Code Playgroud)

for(; ; ) {
   try {
      iValue = Level3Throw(iValue);
   }
   catch(InvalidOperationException) {
      iValue += 3;
   }
   lCounter += 1;
   if(DateTime.Now >= sFinish)
       break;
}
Run Code Online (Sandbox Code Playgroud)

相差20倍。第二个片段慢了 20 倍。