Live data from Hacker News

Python 3.11: “Zero cost” exception handling

bugs.python.org

91–96 of 96 posts

Re: Python 3.11: “Zero cost” exception handling

#91
post #56

Earlier quoted context omitted.

There are some weird performance optimizations in Python, e.g., item = some_dict.get(key) if item is None: # key does not exist Versus try: item = some_dict[key] except KeyError: # key does not exist When I tested these (admittedly, a while ago), which one was faster depended on how often the key was missing. If “missing key” was an expected case, the first one was faster. If “missing key” was uncommon, the second wa…

Fun fact: all those approaches use multiple dict lookups, just of different dicts. First approach is looking for `get` in `type(some_dict).__dict__` and then for `key` in `some_dict`. Second approach is looking for `key` in `some_dict`, and then (only if missing) for `KeyError` in the module globals/builtins. If the performance of hash lookups matters, Python is the wrong language for you.

> If the performance of hash lookups matters, Python is the wrong language for you.

Announcement to Python programmers: “Don’t bother trying to improve the performance of your Python code! If performance matters, just completely rewrite your code in a different language!”

I don’t know how to respond to that, except to disagree with the underlying assumptions that (1) there is a “right language”, (2) if performance matters, Python is not a suitable language, or (3) people are generally in a position to choose which language a project is written in.

Even if performance matters, it is not the only thing that matters. When you choose a language, there are necessarily tradeoffs... everything from the skillset of your team, to the ecosystem of libraries available affects that decision. Finally, there are projects already written in Python.

Re: Python 3.11: “Zero cost” exception handling

#92
post #22

Earlier quoted context omitted.

Exceptions always have a cost. What happened with many C++ runtimes is that they moved the execution cost of exceptions almost entirely into the exception raising mechanism so that the path of execution that does not raise exceptions has no overhead due to exceptions. This was not the case with the Python runtime. The "zero cost" implementation for C++ exceptions in the case of ELF binaries means storing a bunch of s…

Note that the generated instructions - even if they are never run as in [1] - still consume cache and might hinder further optimizations. Which is why `noexcept` is becoming more popular. And because there is no GC, code must be written to be exception-safe in all conditions which is often forgotten. 1: https://godbolt.org/z/bKfG14P64 - the difference between `e()` and `n()` is that one is marked `noexcept`. Both `f(…

There is GC in C++/CLI, Unreal C++, and the optional C++11 API, which is getting dropped in C++23, though.

Re: Python 3.11: “Zero cost” exception handling

#93
post #89

Earlier quoted context omitted.

Couldn't the runtime just allocate a specific Python object representing the case where the iterator is complete? Make that object implementation-specific, hide it as best as you can, write documentation stating that users should not use this value directly, and if they do - they voided the warranty, and should expect evil to befall them. (ultimately, you can't prevent the user from doing really dumb things e.g. edit…

You do that with one thing, okay, maybe it works. You do that with two or more of the protocols that Python has that use return values for return values ans exceptions for flow control signals and...you make it a lot harder to work with them, especially in conjunction.

Can you give an example of this? I can't think of any myself - generators also raise a StopIteration exception, for instance, so they could use the same value.

Re: Python 3.11: “Zero cost” exception handling

#94
post #21

The tenacity of people getting excited over micro optimizations in Python for more than two decades is remarkable. Nothing has happened despite monumental speed programs that were broadly advertised and marketed to corporations. Meanwhile, SBCL has an industrial strength compiler that predates Python and its trademark (the SBCL compiler was called "Python" before the trademark, thereby invalidating it). Python (the l…

It's when you put all these small optimizations together that it leads to something remarkable. It's analogous to video codecs: there are a bunch of individual optimizations that alone don't look that impressive, only saving ~1% here or there. But once they all are working together, you see savings of 10-50%.

Yeah but Python is on the order of 100x slower than "fast" languages. 50% faster would obviously be nice but it's not really going to make Python a fast language.

Re: Python 3.11: “Zero cost” exception handling

#95
post #3

Earlier quoted context omitted.

> I've felt weird using exceptions like that How should they be used instead? Maybe I don't understand what you mean by "idiomatic control flow uses exceptions" - could you give an example. Maybe there is some use of exceptions that I'm not quite familiar with in Python.

This covers it very well: https://devblogs.microsoft.com/python/idiomatic-python-eafp-... In particular, this is not idiomatic python: if "key" in dict_: value += dict_["key"] But this is: try: value += dict_["key"] except KeyError: pass I too hate using the exception handling in this way, and if you aren't careful, you end up papering over other unexpected exceptions in your code, so you have to be (A) very specific…

The second 'key in dict' option is not thread safe if dict_ is not local (another thread may delete the entry between the existence check and use). This is a good reason why the exception handling approach is a better idiom.

The exception handling approach may also be faster if your code cares (may, because I don't know if the cost of calculating the hash of "key" twice is cheaper than the exception handling overhead).

Re: Python 3.11: “Zero cost” exception handling

#96
post #22

Earlier quoted context omitted.

Exceptions always have a cost. What happened with many C++ runtimes is that they moved the execution cost of exceptions almost entirely into the exception raising mechanism so that the path of execution that does not raise exceptions has no overhead due to exceptions. This was not the case with the Python runtime. The "zero cost" implementation for C++ exceptions in the case of ELF binaries means storing a bunch of s…

Excellent post! Python Bytecode is a little more naive / high level than this though, so stuff like exceptions and their nested handlers are actually implemented in the VM itself. The VM has essentially a second stack for exception and context manager blocks. The compiled bytecode essentially looks like this: SETUP_TRY 10 # address where exceptions will be handled some stuff that might explode POP_BLOCK JUMP 20 # jum…

> Python's bytecode compiler is generally a 1:1 translation of the AST; it never optimizes

I thought python had a "peephole optimizer" that optimises?

Post reply on HN