Live data from Hacker News

Avoid exception throwing in performance-sensitive code

lemire.me

101–110 of 243 posts

Re: Avoid exception throwing in performance-sensitive code

#101

Earlier quoted context omitted.

Seems like a language design flaw that this is slow. Imo Rust got this right by making "exceptions" nothing special, just a data type holding an error which can be processed just as fast as anything else.

Which is not to suggest you should be using exceptions for flow control.

Well, if that's the only "escape hatch" you have, because otherwise the language authors decided to limit what you can do with control flow...

Re: Avoid exception throwing in performance-sensitive code

#102

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

For Java see The Exceptional Performance of Lil' Exception from Aleksey Shipilëv, https://shipilev.net/blog/2014/exceptional-performance. As always, Shipilëv does a fantastic job at explaining inner details of the JVM and observed performance profile.

A few years ago, I got hit by the high cost of an hidden exception (used for flow control by the JDK) while using LocalDate#format to parse a valid date. It was fun to troubleshoot and fix OpenJDK https://unportant.info/using-exceptions-for-flow-control-is-...

I would be interested in reading similar articles for other languages.

Re: Avoid exception throwing in performance-sensitive code

#103
post #84

Earlier quoted context omitted.

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

You seem to believe options B to D are not available to programmers in languages with exceptions. The real value comes from making option E much more unlikely: ignoring both the result and error value altogether, because you relied on the side effect of the function you called.

Re: Avoid exception throwing in performance-sensitive code

#104
i wonder how feasible it would be to implement a syntax coloring mode that provides some indication of instruction count from static analysis. so not quite dynamic profiling, but rather something that uncovers (sometimes) surprising implementation details like this and creates a better sense for what the compiler is doing under the hood.

Re: Avoid exception throwing in performance-sensitive code

#105

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)

Re: Avoid exception throwing in performance-sensitive code

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

The Rust Result type combined with mandatory error handling leads to very robust programs. It is also easier to reason about, as there is no hidden (non-local) control flow. Exceptions are unergonomical and slow.

Re: Avoid exception throwing in performance-sensitive code

#107
post #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.

> It's very hard to write exception safe code in C++.

How? As long as RAII is used it's basically for free.

Re: Avoid exception throwing in performance-sensitive code

#109
post #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 re…

> Code emitting exceptions also have no knowledge who (if anyone) is going to handle their output.

This is no different from code returning a regular value. When writing `return -EINVAL;` or `return 0, fmt.Errorf("")` or `return Err(something)`, you have no idea who (if anyone) is going to handle your output.

Also, one reasonable way of implementing exceptions could be exactly to translate all functions that can throw exceptions to functions returning a Result type, and translating function calls to such functions to the equivalent of pattern matching on that return. Of course, this mostly forces the language to only support checked exceptions (otherwise this overhead would be added to all function calls, even those that can't actually fail).

Most languages that implement exceptions have chosen a different trade-off though: make exceptions costly to throw, but make sure they have 0 cost on the happy path. Happy-path code becomes more efficient than it is possible to be in a language which uses return values for errors (since there is no need to check the result before using it), but the unhappy path becomes significantly worse.

Re: Avoid exception throwing in performance-sensitive code

#110

This post is poorly named. What it's saying is to avoid throwing exceptions for normal flow control, and just use them for exceptional cases (file not found, etc). Performance-sensitive code or not, exceptions for exceptional situations are not going to hinder the app's performance until the exceptional situation becomes common (unless your language does lots of exception setup work on the happy path - which most hav…

This! I'd like to think exceptions are reasonable as a terminal state for a particular user workflow, which sometimes even end up having the program terminated. Examples include "unexpected I/O, corrupt files etc."

Exceptions should never be used if the control flow has means to recovery. For example, if-else statements with more different, downstream instructions.

Post reply on HN