Hacker News
points by guipsp 2 days ago | 0 comments
This is numba?
[–] ajross 2 days ago
Yeah, this is numba. I find it really frustrating the extent to which people don't know about it.

Folks, numba is great. To first approximation: write your python function to "look like C"[1] and work over the numpy arrays you probably already have and understand, put a "@jit" decorator on it, and you're done. It JITs and runs your code natively at native performance.

With some extra effort, there are features for SIMD vectorization and thread parallelism, and even GPU backends (that, full disclosure, I've been pretty frustrated by -- but they do work).

[1] Which is to say, don't touch Python interpreter data structures. No dicts or objects or lists or strings, etc... If you're bound by the interpreter[2] you're bound by the interpreter and nothing is going to help you.

[2] A corrolary here is that the kind of C code numba is NOT good for is "following pointers between structs", which is something that can't be expressed in either python or numpy.

[–] Dylan16807 2 days ago
> No dicts or objects or lists or strings, etc.

That's a really intense restriction. Sounds like the name fits; it's not general purpose, it's jit for number crunching and little else.

I'm not sure exactly what you mean by "bound by the interpreter" but there's nothing about touching those data structures that requires the interpreter to be involved in most cases. The problem of slow APIs can be solved by the JIT having intimate knowledge of python's internals, can't it?

[–] ajross 2 days ago
> That's a really intense restriction.

Is it? An object field access in python is a dynamic hash lookup followed by a method call as a fallback (itself involving hashed lookups up the class hierarchy). That's not an "interpreter vs. native" kind of thing, that's just the semantics of the language that have to be preserved. And that's just not going to be "fast" in the way that the user of a JIT would want. Code dominated by Python datastructures is going to be "slow" in ways that JITs can't fix, ever.

Which is why Python appears to have given up on the effort in this space. PyPy too[1] really never delivered on the desired performance gains (like 5x or so on typical code) without forcing the user into careful optimization.

Numba, to its credit, doesn't even try. It falls back to python if it must for python stuff, but is quite clear that it's providing no benefit if that's what you're doing. And the stuff it does do is obvious and clean and extremely useful.

[1] PyPy is also looking pretty moribund recently.

[–] Dylan16807 2 days ago
A hash lookup can be very fast. There's no reason for it to be slow when it doesn't need to invoke the fallback. JITs can't remove the slowest case but they can make the normal case very fast. Saying it can't be fast ever is a huge cop-out.
[–] zahlman 1 day ago
Yes, Python's hash lookups are actually pretty good. The comments in the implementation are an interesting read.

But that doesn't help much if/when you're doing two hash lookups per iteration just to find two small integers to add together.

[–] ajross 2 days ago
> Saying it can't be fast ever is a huge cop-out.

Maybe, but the world is still waiting for the counterexample. Python is simply not a runtime well-suited to optimization.

In the meantime, those of us who actually enjoy real HPC problems are using numba and rolling our eyes about all the confuffery around JITs. Maybe one will arrive that proves us wrong, but numba is fast today.

[–] Dylan16807 2 days ago
LuaJIT has the same dynamism with dictionaries and it's very fast at accessing them in JIT code.

I don't have enough experience with PyPy to say much about it.

[–] strenholme 1 day ago
I have moved my more complex scripting from Perl/PHP/Python to Lua for a lot of reasons. One being that Lua (even PUC Lua) is a good deal faster than Python (or /bin/sh); another is that, if I want even more speed, I can use LuaJIT (which keeps me stuck at Lua 5.1, but Lua 5.1 is perfect for my needs).

I wish Lua 5.1 could become part of POSIX; there are a lot of implementations of it out there.

[–] zahlman 1 day ago
Probably "bound by the data model" is a better way to put it. The interpreter might not be required to touch the data structure, but you have to do a lot of touching of the data structure to get the work done (plus, its mere existence ruins any dream of cache coherency).
[–] Dylan16807 1 day ago
For most objects, you access it directly and nothing weird happens, right?

Can you not mostly cache whether anything weird needs to happen and do the direct access with minimal overhead?

You said elsewhere "But that doesn't help much if/when you're doing two hash lookups per iteration just to find two small integers to add together." but looking up two fields isn't inherently a very big overhead. And you can cache the actual hash, and if you want to you can make sure the fields on similar objects have a consistent offset and cache that offset to make it even faster. This code using lots of objects is presumably not the core number crunching on arrays; we're doing more logic per access and we can handle a few instructions to get a value.

[–] sgarland 2 days ago
I posted it as well before scrolling down and seeing yours. Deleted mine, as your post goes into much more detail.

I don’t know how people who’ve worked with Python and been frustrated with its performance don’t know about Numba.

[–] bheztio 2 days ago
Last I tried numba, admittedly a long time ago, it was a pain due to extensive system requirements or alternatively requiring use of conda, which I dislike (for many reasons, but it's besides the point - I want to use standard python tools). Did they start to bundle their dependencies or..?
[–] ajross 2 days ago
PyPI integration is clean; "pip install numba" does what you expect, uv works fine, yada yada.

The one aesthetic gripe I have is that the LLVM included is a fork. It won't even try to work with the system LLVM and insists on installing a huge wheel with custom binaries. But on a modern system an extra LLVM is noise, so I guess I don't care that much.

[–] pitrou 1 day ago
> The one aesthetic gripe I have is that the LLVM included is a fork.

It's not technically a fork, it's a standalone build of vanilla LLVM (ok, there are a couple patches: https://github.com/numba/llvmlite/tree/main/conda-recipes).

> It won't even try to work with the system LLVM and insists on installing a huge wheel with custom binaries.

Not only does LLVM not have a stable ABI, it doesn't even have a stable API. It's difficult to write code that works reliably against a non-trivial number of LLVM major versions.

For the record, here is the LLVM compatibility table for llvmlite versions (llvmlite is the Python-C++ shim that Numba uses to talk to LLVM): https://llvmlite.readthedocs.io/en/latest/#llvm-compatibilit...

If you want a Numba linked against your system LLVM, the solution would be for your distribution to provide a system package for Numba (and llvmlite).

[–] zahlman 1 day ago
I don't understand why your comment was dead; I've vouched for it.
[–] ainch 2 days ago
if you want GPU-backed/compiled numpy code then JAX is also a good option.
[–] rich_sasha 2 days ago
Not really. Numba is great at optimizing numpy code but not necessarily other general Python code.