Live data from Hacker News

Avoid exception throwing in performance-sensitive code

lemire.me

181–190 of 243 posts

Re: Avoid exception throwing in performance-sensitive code

#181
post #8

Different languages have different exception handing optimizations. A Java version of the example can run very slow or very fast, depending on how clever you are. When a new RuntimeException is thrown half the time, the example runs about 650 times slower when compared to a function which adds up the integers without using exceptions. If I define an exception subclass which doesn't fill in the stack trace, then it ru…

Moreover, different languages implement the exception handling differently.

The article focuses on C++, which has a notion of object destructors (most – but not all – programming languages don't have the destructors).

Implications for the exception handling are manyfold: upon an entry into a «try» block, a C++ compiler has to account for all objects created at the method (or function) scope up until this point and register their corresponding destructors in the exception unwinding table. Then, since C++ allows objects to be created on the stack (via RAII or an explicit object declaration), the call frame has to be correctly accounted for as well. Both of which are computationally expensive things to do.

When an exception is thrown out, the «throw» statement results in a reverse walk back of the registered destructors first (apart from the objects created on the heap), and then adjusting the frame pointer and placing an exception object on the stack before returning from the method's (or function's) exception handler.

All of that takes many CPU cycles and wreaks havoc on instruction scheduling, pipelines, the TLB and stuff, therefore making the exception handling very expensive in C++ with little room left for optimisations. Exception handling performance in earlier revisions of C++ was abysmal. It is also all C++ specific and does not apply to other programming languages.

Java, for instance, doesn't do that, and leaves the heap clean-up (where all Java objects are created anyway) to the garbage collector, so the exception handling is less taxing in Java – at the exception raising point.

P.S. The above is a gross oversimplification of how the exception handling works in C++, but it should it give a rough idea of why the author has observed a slowdown at an orders of magnitude scale.

Re: Avoid exception throwing in performance-sensitive code

#182
post #43

Exceptions are starting to feel like a legacy programming paradigm to me. Rust & Go have, at least in a practical programming context, shown that errors-as-values has far less footguns and encourages better error handling practices than exceptions, which often are treated as an afterthought or end up being abused like in this post. Whenever I'm writing Python or Java I can't help but feel anxious about calling a func…

I think what Java got wrong was allowing catching unchecked exceptions. If Java had only allowed recovering from checked exceptions, it would have been a very similar experience to Rust's Result and panic. Instead, the trend was to avoid using checked exceptions at all, which perpetuated the crazy situation we're in where library code can suddenly abort and the author shrugs and says "shoulda read the docs".

[deleted]

Re: Avoid exception throwing in performance-sensitive code

#183

Earlier quoted context omitted.

I mean stack overflows or out of memory errors. It might fail one request, but no reason to fail all others.

That's a very specific case, that could be handled non-trivially. Usually your HTTP framework will already have this implemented, i.e. a panic in a request handler will be "caught", converted to some 500 response, and should not affect other requests.

My point is that this is in no way different from any other class of errors, _except_ in those cases where it is. It's practical to assume all errors are handled like this, because this catch all needs to exist anyway. And unless you have _very specific needs_, this can be automated.

Re: Avoid exception throwing in performance-sensitive code

#184

Earlier quoted context omitted.

> Unrecoverable errors are things like stack overflows or out of bounds array access. There is no reasonable way to soldier on after this, so the program should just end No, I wholeheartedly disagree with this. It's the equivalent of exit(1) some way down the stack. Whats recoverable or not depends on the use case and is a decision to be made by the caller of a function, not the implementor.

GP might have been referring to undefined/invalid behaviour (whether in the language or in some OS syscall or whatever). After the demons came out of your nose you can never fix the problem, so there is no point trying to handle the error. Otherwise I agree with you, that library code should not fail/crash/exit(1) just because of some judgement about recoverability, and out to clean up after itself before passing con…

GP might have meant undefined behavior, but specifically mentioned stack overflows and out of bounds array access as unrecoverable errors. These sound brutal, but are in fact all but undefined. Proper handling is expected in the large class of applications which run as servers.

Re: Avoid exception throwing in performance-sensitive code

#185

Earlier quoted context omitted.

Return an error or fatally exit the program, depending.

If you return an error, it needs to be checked for in every place where this function is called. Yes, I know C libraries and OS APIs do this often, but that's C, it's the only thing it can do. This just invites human error. Besides, it's often desirable to handle multiple different error conditions (arising from different steps as you process the input data) in one place, which is complicated with this approach. Java…

I'm not arguing for or against this approach, merely responding to a question with a factual answer.

But since you brought it up ;) I bounce back and forth between which approach I like. Sometimes exceptions seem bulky and unwieldy and honestly a bit lazy. Returning an error feels verbose and annoying and bulky as well. But it also feels like returning an error forces you to think about what should happen, where exceptions let you kick the can down the road.

Neither are great, but I find that code that uses exceptions ends up being poorer in design and functioning, but also errors-on-return tends to be harder to read.

Re: Avoid exception throwing in performance-sensitive code

#186

In python, exceptions for control flow is how the language works . Think about that.

Thank you! Was starting to think I got all my codebase wrong and misunderstood what is « pythonic » So doing this in python is ok (fastest way to check if a key is in a dict is catching KeyError for example, if I remember correctly)

Yes, do not let the HN anti-exception crusaders gaslight you. I still remember when I "discovered" exceptions in programming - "this is so much cleaner!"

All this theoretical mumbo jumbo is just noise. Very few of us are dealing with the type of programming every day where exceptions can actually become a noticeable bottleneck.

Re: Avoid exception throwing in performance-sensitive code

#187

Earlier quoted context omitted.

That's a very specific case, that could be handled non-trivially. Usually your HTTP framework will already have this implemented, i.e. a panic in a request handler will be "caught", converted to some 500 response, and should not affect other requests.

My point is that this is in no way different from any other class of errors, _except_ in those cases where it is. It's practical to assume all errors are handled like this, because this catch all needs to exist anyway. And unless you have _very specific needs_, this can be automated.

I think conflating these two into one paradigm is worse. The catch-all (exceptions) style is nice only for a few very specific cases, like the request handler example. Everywhere else I want to either bubble up (like exceptions, but Result and ? sugar is as good or better), OR I want to handle the error. For the latter case, exceptions are not good at all.

Re: Avoid exception throwing in performance-sensitive code

#189
post #8

Different languages have different exception handing optimizations. A Java version of the example can run very slow or very fast, depending on how clever you are. When a new RuntimeException is thrown half the time, the example runs about 650 times slower when compared to a function which adds up the integers without using exceptions. If I define an exception subclass which doesn't fill in the stack trace, then it ru…

I must admit I use exceptions heavily for validation, e.g. checking input at API bounds. It makes the code fairly clean. I would imagine this is considered bad practice, but if there was no overhead this seems preferable over wrapping every call in some wrapper object. Any good links to further info on this?

> I use exceptions heavily for validation

This fits within my understanding of a reasonable use for exceptions - usually these are in the form of assertions, which themselves throw exceptions but can be turned off at runtime if you don't expect to ever see this condition in real production circumstances.

Re: Avoid exception throwing in performance-sensitive code

#190
post #43

Exceptions are starting to feel like a legacy programming paradigm to me. Rust & Go have, at least in a practical programming context, shown that errors-as-values has far less footguns and encourages better error handling practices than exceptions, which often are treated as an afterthought or end up being abused like in this post. Whenever I'm writing Python or Java I can't help but feel anxious about calling a func…

> feel anxious about calling a function and having absolutely no idea if or what exceptions it might throw

You can try doing what most of my coworkers do and just not care.

Post reply on HN