C# 中的异常有多昂贵?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/891217/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 08:38:47  来源:igfitidea点击:

How expensive are exceptions in C#?

c#exception

提问by Chance

How expensive are exceptions in C#? It seems like they are not incredibly expensive as long as the stack is not deep; however I have read conflicting reports.

C# 中的异常有多昂贵?只要堆栈不深,它们似乎并不昂贵;但是我读过相互矛盾的报告。

Is there definitive report that hasn't been rebutted?

有没有没有被反驳的最终报告?

采纳答案by Robert Paulson

Jon Skeet wrote Exceptions and Performance in .NETin Jan 2006

Jon Skeet在 2006 年 1 月撰写了 .NET中的异常和性能

Which was updated Exceptions and Performance Redux(thanks @Gulzar)

已更新异常和性能 Redux(感谢 @Gulzar)

To which Rico Mariani chimed in The True Cost of .NET Exceptions -- Solution

Rico Mariani 在The True Cost of .NET Exceptions 中提到的问题——解决方案



Also reference: Krzysztof Cwalina - Design Guidelines Update: Exception Throwing

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

回答by Colin Burnett

I guess I'm in the camp that if performance of exceptions impacts your application then you're throwing WAYtoo many of them. Exceptions should be for exceptional conditions, not as routine error handling.

我想我在营地,如果你的应用程序,那么你会抛出异常影响性能WAY太多了。异常应该是针对异常情况,而不是常规错误处理。

That said, my recollection of how exceptions are handled is essentially walking up the stack finding a catch statement that matches the type of the exception thrown. So performance will be impacted most by how deep you are from the catch and how many catch statements you have.

也就是说,我对如何处理异常的回忆基本上是在堆栈中查找与抛出的异常类型匹配的 catch 语句。因此,性能将受您与 catch 的深度以及您拥有的 catch 语句的数量影响最大。

回答by Jon Limjap

Barebones exception objects in C# are fairly lightweight; it's usually the ability to encapsulate an InnerExceptionthat makes it heavy when the object tree becomes too deep.

C# 中的准系统异常对象相当轻量级;InnerException当对象树变得太深时,通常是封装一个的能力使它变得沉重。

As for a definitive, report, I'm not aware of any, although a cursory dotTrace profile (or any other profiler) for memory consumption and speed will be fairly easy to do.

至于最终的报告,我不知道任何,尽管用于内存消耗和速度的粗略的 dotTrace 配置文件(或任何其他分析器)将相当容易做到。

回答by Gishu

The performance hit with exceptions seems to be at the point of generating the exception object (albeit too small to cause any concerns 90% of the time). The recommendation therefore is to profile your code - if exceptions arecausing a performance hit, you write a new high-perf method that does not use exceptions. (An example that comes to mind would be (TryParse introduced to overcome perf issues with Parse which uses exceptions)

异常对性能的影响似乎是在生成异常对象时(尽管在 90% 的情况下太小而不会引起任何问题)。因此,该建议是分析代码-如果异常造成性能损失,你写的不使用例外,一个新的高PERF方法。(想到的一个例子是(引入 TryParse 以克服使用异常的 Parse 的性能问题)

THat said, exceptions in most cases do not cause significant performance hitsin most situations - so the MS Design Guidelineis to report failures by throwing exceptions

也就是说,在大多数情况下,异常在大多数情况下不会导致显着的性能下降- 所以MS 设计指南是通过抛出异常来报告失败

回答by Helge Klein

Having read that exceptions are costly in terms of performance I threw together a simple measurement program, very similar to the one Jon Skeet published years ago. I mention this here mainly to provide updated numbers.

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

It took the program below 29914 milliseconds to process one million exceptions, which amounts to 33 exceptions per millisecond. That is fast enough to make exceptions a viable alternative to return codes for most situations.

程序用了 29914 毫秒以下的时间来处理 100 万个异常,相当于每毫秒 33 个异常。这足以使异常成为大多数情况下返回代码的可行替代方案。

Please note, though, that with return codes instead of exceptions the same program runs less than one millisecond, which means exceptions are at least 30,000 times slower than return codes. As stressed by Rico Marianithese numbers are also minimum numbers. In practice, throwing and catching an exception will take more time.

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

Measured on a laptop with Intel Core2 Duo T8100 @ 2,1 GHz with .NET 4.0 in release build not run under debugger(which would make it way slower).

在配备 Intel Core2 Duo T8100 @ 2,1 GHz 和 .NET 4.0 的笔记本电脑上测量,不在调试器下运行(这会使其变慢)。

This is my test code:

这是我的测试代码:

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;
}

回答by mpen

In my case, exceptions were veryexpensive. I rewrote this:

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

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];
        }
    }
}

Into this:

进入这个:

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]];
    }
}

And noticed a good speed increase of about 30 seconds. This function gets called at least 32K times at startup. Code isn't as clear as to what the intention is, but the cost savings were huge.

并注意到大约 30 秒的良好速度增加。该函数在启动时至少被调用 32K 次。代码的意图并不明确,但节省的成本是巨大的。

回答by Alex

I did my own measurements to find out how serious the exceptions implication is. I didn't try to measure the absolute time for throwing/catching exception. What I was mostly interested is how much slower a loop will become if an exception is thrown in each pass. The measuring code looks like this

我进行了自己的测量,以了解异常含义的严重程度。我没有尝试测量抛出/捕获异常的绝对时间。我最感兴趣的是如果每次传递都抛出异常,循环会变慢多少。测量代码看起来像这样

     for(; ; ) {
        iValue = Level1(iValue);
        lCounter += 1;
        if(DateTime.Now >= sFinish) break;
     }

vs

对比

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

The difference is 20 times. Second snippet is 20 times slower.

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

回答by d.na

Just to give my personnal experience : I'm working on a program that parses JSON files and extracts data from them, with NewtonSoft.

只是为了提供我的个人经验:我正在使用 NewtonSoft 开发一个解析 JSON 文件并从中提取数据的程序。

I rewrote this :

我重写了这个:

  • Option 1, with Exceptions.
  • 选项 1,有例外。
try
{
    name = rawPropWithChildren.Value["title"].ToString();
}
catch(System.NullReferenceException)
{
    name = rawPropWithChildren.Name;
}

To this :

对此:

  • Option 2, without Exceptions.
  • 选项 2,没有例外。
if(rawPropWithChildren.Value["title"] == null)
{
    name = rawPropWithChildren.Name;
}
else
{
    name = rawPropWithChildren.Value["title"].ToString();
}

Ofc you don't really have context to judge about it, but here are my results :
(In debug mode)

OFC你真的没有上下文它法官,但这里是我的结果:
在调试模式

  • Option 1, with Exceptions. 38.50s

  • Option 2, with Exceptions. 06.48s

  • 选项 1,有例外。 38.50s

  • 选项 2,有例外。 06.48s

To give a little bit of context, I'm working with thousands of json properties that can be null. Exceptions were thrown way too much, like maybe during 15% of the execution time. Well, not really precise but they were thrown too many times. I wanted to fix this so I changed my code, and I did not understand why the execution time was so much faster. That was because of my poor exception handling.

为了提供一点上下文,我正在使用数千个可以为 null 的 json 属性。异常被抛出的方式太多了,比如可能在 15% 的执行时间内。嗯,不是很精确,但它们被扔了太多次。我想解决这个问题,所以我改变了我的代码,但我不明白为什么执行时间要快得多。那是因为我糟糕的异常处理。

So, what I've learned from this : I need to use exceptions only in particular cases and for things that can't be tested with a simple conditionnal statement. They also must be thrown the less often possible.

所以,我从中学到了什么:我只需要在特定情况下以及无法用简单的条件语句测试的情况下使用异常。它们也必须尽可能少地被抛出。

This is kind of a random story for you, but I guess I would definitely think twice before using exceptions in my code from now !

这对你来说是一个随机的故事,但我想从现在开始在我的代码中使用异常之前我肯定会三思而后行!

回答by DragonSpit

I recently measured C# exceptions (throw and catch) in a summation loop that threw an arithmetic overflow on every addition. Throw and catch of arithmetic overflow was around 8.5 microseconds = 117 KiloExceptions/second, on a quad-core laptop.

我最近在求和循环中测量了 C# 异常(抛出和捕获),每次加法都会引发算术溢出。在四核笔记本电脑上,算术溢出的抛出和捕获大约为 8.5 微秒 = 117 KiloExceptions/秒。

回答by Kalpesh Popat

Exceptions are expensive, but there is more to it When you want to choose between Exception and Return codes.

异常很昂贵,但是当您想在异常和返回代码之间进行选择时,还有更多。

Historically speaking the argument was, exception ensures that code is forced to handle the situation whereas return codes can be ignored, i never favoured these arguments as no programmer will want to ignore and break their codes on purpose - especially a good test team / or a well written test case will definitely not ignore return codes.

从历史上讲,这个论点是,异常确保代码被迫处理这种情况,而返回码可以被忽略,我从不赞成这些论点,因为没有程序员愿意故意忽略和破坏他们的代码——尤其是一个好的测试团队/或编写好的测试用例绝对不会忽略返回码。

From modern programming practices point of view, managing exceptions need to be looked not only for their cost but also for their viability.

从现代编程实践的角度来看,管理异常不仅需要考虑其成本,还需要考虑其可行性。

1st. Since most front end will be disconnected from the API that is throwing exception. eg a mobile app utilising rest api. The same api can also be used for an angular js based web frontend.

第一。由于大多数前端将与抛出异常的 API 断开连接。例如使用rest api的移动应用程序。相同的 api 也可以用于基于 angular js 的 Web 前端。

Either scenario will prefer Return Codes instead of exception.

这两种情况都更喜欢返回代码而不是异常。

2nd. Now a days hackers randomly attempt to break all web utilities. In such scenario if they are constantly attacking your apps login api and if the app is constantly throwing exception then you will end up dealing with thousands of exceptions a day. Ofcourse many will say firewall will take care of such attacks, however not all are spending money to manage a dedicated firewall or an expensive anti-spam service, it is better that your code is prepared for these scenarios.

第二。现在一天黑客会随机尝试破坏所有网络实用程序。在这种情况下,如果他们不断攻击您的应用程序登录 api,并且应用程序不断抛出异常,那么您最终将每天处理数千个异常。当然,很多人会说防火墙会处理此类攻击,但并非所有人都花钱来管理专用防火墙或昂贵的反垃圾邮件服务,最好为这些场景准备好您的代码。