IT TIP

C #의 예외는 얼마나 비쌉니까?

itqueen 2020. 11. 1. 19:06
반응형

C #의 예외는 얼마나 비쌉니까?


C #의 예외는 얼마나 비쌉니까? 스택이 깊지 않은 한 엄청나게 비싸지 않은 것 같습니다. 그러나 나는 상충되는 보고서를 읽었습니다.

반박되지 않은 확실한 보고서가 있습니까?


Jon Skeet은 2006 년 1 월 에 .NET 에서 예외 및 성능을 작성했습니다.

예외 및 성능 Redux 가 업데이트되었습니다 (@Gulzar에게 감사드립니다)

Rico Mariani가 The True Cost of .NET Exceptions-Solution


또한 참조 : Krzysztof Cwalina- 디자인 지침 업데이트 : 예외 발생


예외는 성능 측면에서 비용이 많이 든다는 것을 읽은 후 몇 년 전에 Jon Skeet이 발표 한 것과 매우 유사한 간단한 측정 프로그램을 작성했습니다 . 여기서는 주로 업데이트 된 번호를 제공하기 위해 언급합니다.

프로그램이 1 백만 개의 예외를 처리하는 데 29914 밀리 초 미만이 걸렸으며 이는 밀리 초당 33 개의 예외에 해당 합니다. 이는 대부분의 상황에서 예외를 반환 코드에 대한 실행 가능한 대안으로 만들기에 충분히 빠릅니다.

그러나 예외 대신 반환 코드를 사용하면 동일한 프로그램이 1 밀리 초 미만으로 실행됩니다. 즉, 예외가 반환 코드보다 30,000 배 이상 느립니다 . Rico Mariani가 강조 했듯이이 숫자도 최소 숫자입니다. 실제로 예외를 던지고 잡는 데 더 많은 시간이 걸립니다.

디버거에서 실행되지 않는 릴리스 빌드의 .NET 4.0이 포함 된 Intel Core2 Duo T8100 @ 2,1GHz 노트북에서 측정되었습니다 (속도가 느려질 수 있음).

이것은 내 테스트 코드입니다.

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

나는 캠프에있어 생각하는 경우 응용 프로그램이 다음 던지고있다 예외에 미치는 영향의 성능 WAY를 그들 중 너무 많은. 예외는 일상적인 오류 처리가 아닌 예외적 인 조건에 대한 것이어야합니다.

즉, 예외가 처리되는 방법에 대한 기억은 본질적으로 던져진 예외 유형과 일치하는 catch 문을 찾는 스택을 걷는 것입니다. 따라서 성능은 캐치에서 얼마나 깊은 지와 얼마나 많은 캐치 문을 가지고 있는지에 따라 가장 큰 영향을받습니다.


제 경우에는 예외가 매우 비쌌습니다. 나는 이것을 다시 썼다.

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

이것으로 :

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

그리고 약 30 초의 좋은 속도 증가를 발견했습니다. 이 함수는 시작시 최소 32K 번 호출됩니다. 의도가 무엇인지 코드는 명확하지 않지만 비용 절감은 엄청났습니다.


C #의 Barebones 예외 개체는 상당히 가볍습니다. 일반적으로 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.


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.


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 are causing 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)

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


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

I rewrote this :

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

To this :

  • Option 2, without Exceptions.
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)

  • Option 1, with Exceptions. 38.50s

  • Option 2, with Exceptions. 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.

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 !


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.

참고URL : https://stackoverflow.com/questions/891217/how-expensive-are-exceptions-in-c

반응형