Live data from Hacker News

Avoid exception throwing in performance-sensitive code

lemire.me

51–60 of 243 posts

Re: Avoid exception throwing in performance-sensitive code

#51

I'm completely ignorant of the subject, but most surprising to me in his example was that the compiler didn't optimize away the inefficiency. Is there something about exception handling that makes it not get taken into account during optimization?

C++ exceptions and by extension Rust panics and C# exceptions (with caveats) involve stack unwinding as well as gathering of corresponding details and producing an exception object (C#). It is very expensive and using it as a normal condition in general is not the best idea. It is by definition cannot be optimized in a way that gets both good performance and keeps all existing side effects. That's why Rust's Result i…

In the C# stdlib there is at least currently the Task and ValueTask pair, where the latter is a struct optimized for 'failure is rare and success is synchronous' that degrades smoothly to the former, which can represent asynchronous computation and lets you recover failure exceptions w/stack without having to ever actually throw. I do wish the async part was decoupled from it, but it's nice that all the error information is preserved if used correctly.

Re: Avoid exception throwing in performance-sensitive code

#52
post #24

excepts were the only way in CLU to handle control flow. something like while read_character { handle_character } except_when end_of_file { return string } and it did this primarily because it was typesafe: read_character always returned a character, and the "except" cases could return what they were declared to return. "except" was far from exceptional. There's nothing ineffecient about that, it's meatly linked up a…

Returning an option sumtype is also typesafe.

Exceptions have to walk up the stack until a suitable handler is found, that handler can't know ahead of time where the value is coming from or if it will ever arrive - just what type it will be if it arrives. Code emitting exceptions also have no knowledge who (if anyone) is going to handle their output. It is a nonlocal goto in reverse.

Compared to regular functional returns there are so many unknowns. I'd prefer returning an option value any day of the week.

Re: Avoid exception throwing in performance-sensitive code

#53
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?

Food for thought: what are the expected consequences of the exception?

If the error will stop the program flow and show a warning dialog to the user, it's useless to think too much about performance. More or less the same if it's going to log some message and abort the operation.

What is usually frowned upon is using the exception as a kind of goto for normal flow of the program. Exceptions should be... the exception.

Otherwise all this performance brouhaha is a waste of time.

Re: Avoid exception throwing in performance-sensitive code

#54

I'm completely ignorant of the subject, but most surprising to me in his example was that the compiler didn't optimize away the inefficiency. Is there something about exception handling that makes it not get taken into account during optimization?

C++ exceptions and by extension Rust panics and C# exceptions (with caveats) involve stack unwinding as well as gathering of corresponding details and producing an exception object (C#). It is very expensive and using it as a normal condition in general is not the best idea. It is by definition cannot be optimized in a way that gets both good performance and keeps all existing side effects. That's why Rust's Result i…

Nick Chapsas did a demo of just how much overhead regularly thrown exceptions cause: https://www.youtube.com/watch?v=2f2elFRmeLE

Spoiler, each throw/catch costs 20 microseconds

Re: Avoid exception throwing in performance-sensitive code

#55
post #22

Impossible to avoid in python.. exceptions are even how a simple for loop is implemented under the covers!

Is that still true in recent Python versions? Sounds like low-hanging fruit for perf optimisation.

Using exceptions in python isn't any more expensive than not using exceptions because the interpreter pays the same cost no matter what. It's a core design decision. Changing it would probably break some things.

Re: Avoid exception throwing in performance-sensitive code

#56
post #32
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…

Thanks for this short and fine example of Java optimization. I still have a lingering loathing for the language based on the 2000s era marketing, but technically speaking there's rather a lot to like about the java ecosystem.

Just because it started off that way does not mean it remains so. As a matter of fact, it has come along very nicely in the past few years with many cool features including virtual threads, sealed types, pattern matching, records, and more.

Re: Avoid exception throwing in performance-sensitive code

#57
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".

Re: Avoid exception throwing in performance-sensitive code

#58
post #32

Earlier quoted context omitted.

Thanks for this short and fine example of Java optimization. I still have a lingering loathing for the language based on the 2000s era marketing, but technically speaking there's rather a lot to like about the java ecosystem.

Just because it started off that way does not mean it remains so. As a matter of fact, it has come along very nicely in the past few years with many cool features including virtual threads, sealed types, pattern matching, records, and more.

Yeah to be fair I have to give this same kind of spiel for JavaScript too.

Re: Avoid exception throwing in performance-sensitive code

#59
post #53

Earlier quoted context omitted.

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?

Food for thought: what are the expected consequences of the exception? If the error will stop the program flow and show a warning dialog to the user, it's useless to think too much about performance. More or less the same if it's going to log some message and abort the operation. What is usually frowned upon is using the exception as a kind of goto for normal flow of the program. Exceptions should be... the exception…

"Exceptions should be... the exception."

:)

Re: Avoid exception throwing in performance-sensitive code

#60

I'm a little disappointed that the author doesn't explain why throwing the exception is much slower.

Stack traces. The information required to build a stack trace is deliberately kept off the critical path so it doesn't impact performance during normal operation, but that means that building a stack trace requires going out and fetching the debug symbols and correlating them.

Without stack traces, exceptions are just a type of goto.

Post reply on HN