Live data from Hacker News

Avoid exception throwing in performance-sensitive code

lemire.me

91–100 of 243 posts

Re: Avoid exception throwing in performance-sensitive code

#91
umm the example is contrived, and the title is overly broad. performance-sensitive code has exceptional situations that can either be handled, or should cause the program to abort. performance-sensitive code use libraries that throw exceptions too. or the recommendation here will be to use non-exception-throwing libraries only in performance-sensitive code? that significantly reduces what libraries i can use in my code. my interpretation of the essay is: where possible prefer is/else to try/catch. branching on if/else is easy and inexpensive. try/catch could be expensive if (1) new exception instance is created every time, (2) stack/backtrace is generated. you really want to avoid (2) when all you need from the exception is the information that the abnormal happened. if you can use a singleton exception, you may be able to use try/catch. then you can make the beauty (of the code) judgement later.

Re: Avoid exception throwing in performance-sensitive code

#92
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…

Has it shown this? Are there solid metrics or is it simply because they're popular and it's not the idiomatic way to do things? My understanding is they still have panics anyhow.

Re: Avoid exception throwing in performance-sensitive code

#94

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.

What about dynamic languages? Are they always collecting the stack and keeping it into some exception object that the exception can grab the data from at any time? And if that's the case wouldn't it always be slow regardless of raising or not ?

Re: Avoid exception throwing in performance-sensitive code

#95
post #66
post #36

Earlier quoted context omitted.

This is another reason why Common Lisp style condition system (where exception handlers can execute without unwinding the stack) just seems to work better. If you need the stack, get the stack, if you don't then just use handler-case. I really don't see the downside for any language that has anonymous function literals.

Java has them now but it didn't at the time (and even now they're kind of bodged in IIRC).

I don't think Java has support for CL condition system-style restarts. You're maybe talking about exceptions that simply don't populate the stack trace?

To clarify a bit, in CL, when throwing an exception, you can optionally register one or more "restarts", which are essentially lambdas of 0 or more parameters. When the exception is thrown, the stack is walked to find the appropriate handler, but it is not unwound. Whoever catches the exception will also receive these restart lambdas. If they chose to call one of the lambdas (passing it the proper parameters), stack unwinding will not happen at all, and execution will continue from the place the exception was thrown. Only if none of the restarts are invoked is the stack unwound, and execution continued from the catch block.

For a somewhat trivial example, the CL runtime throws an exception whenever a variable that was not defined is being read. That exception includes a restart that allows you to define a value for the variable - if this is called, execution will continue where the variable was being read, using this value for the undefined variable. Of course, this would be crazy to do automatically, but it is very nifty when debugging, as this option is presented to you in the REPL.

Re: Avoid exception throwing in performance-sensitive code

#96
post #93

This was a fairly common position when I was programming C++ over a decade ago. Performance critical code like game engines, etc used to avoid exceptions like the plague. Not entirely surprised to find that’s still the case.

99.99% (maybe even more) of game engines is not performance critical code though. I guess the reason was a different one: for exceptions to work you need a sane memory model. It's very hard to write exception safe code in C++. A garbage collector is very helpful to accomplish that, and _this_ is the thing that's problematic, because it interferes with the 0.01% performance critical inner loops.

Re: Avoid exception throwing in performance-sensitive code

#97
post #90
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…

Exceptions work well for 2 kinds of error handling: crash and log, and general retry and log. The second one is more cumbersome with return values if the possible errors originate deep in the stack. Beyond a simple retry, Exceptions are not specific enough for handling errors.

Exceptions are typically custom types - you can build an arbitrarily detailed exception taxonomy (typically branching off the language-standard one), and in most (all?) languages supporting exceptions, you can also give them arbitrary state.

You really can't get more specific than that. If exceptions still feel "not specific enough for handling errors", perhaps it's because you're only thinking of most trivial examples, as given by 101 tutorials and people arguing against exception handling?

Re: Avoid exception throwing in performance-sensitive code

#98
post #84

Earlier quoted context omitted.

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

> where library code can suddenly abort and the author shrugs and says "shoulda read the docs". In see no difference. Except for the fact that you don't have the stacktrace (in Go), and unroll the Stack manually. In any case, there'll be a generic catch (whatever you call it) on the top level of your daemon to recover from the failed request and handle the next.

In Go the programmer is forced to make a decision on what to do with the error. Common patterns include (A) return an annotated error, (B) log it and continue, (C) retry, (D) aggregate the errors in some way. If you believe the only way to handle an error is (A), then Go's design makes no sense.

Re: Avoid exception throwing in performance-sensitive code

#99
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…

Rust do still has exceptions, they're just called "results". You can't really have values as exceptions unless you plug a lot of ad-hoc constructs into your language so that they eventually become similar to exceptions [1]: > Add syntactic sugar for working with the Result type which models common exception handling constructs. The whole error handling story with Rust can be summarized as "we have results but want to…

Errors in rust are not exceptions, they're data contained within an `Either` monad (Result)

Additionally, on top of the linked RFC being nearly 9 years old it doesn't at all indicate "we want to have exceptions".

The ? operator allows propogating the errors if they can't be immediately handled (similar to monadic `do` notation, or early returns)

Re: Avoid exception throwing in performance-sensitive code

#100

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.

While you are absolutely right that collecting stack traces is an extremely costly operation, it's not the only problem. For example, in C++, which doesn't collect any kind of stack trace, throwing an exception is still ~1 order of magnitude slower than returning a value through all the layers. Note that this cost only happens when the exception is thrown; exception-based code is otherwise slightly faster than `if ret There is some explanation as to why this happens in this SO response [0]. The gist is that the dynamic nature of exception handling means that the compiler needs to consult runtime type information to decide where to jump when the exception is thrown, which means trawling through some relatively lengthy data structures. Adding to the problem, these data structures are not normally used a lot, so they are very likely not to be cached - though this may change for a program that actually throws exceptions in a hot loop, and the difference may not be as stark.

[0] https://stackoverflow.com/questions/13835817/are-exceptions-...

Post reply on HN