top | item 30904430

Cython is 20

210 points| geococcyxc | 3 years ago |blog.behnel.de

70 comments

order

physicsguy|3 years ago

I love Cython. I really feel like it's the right balance of usability and allowing you to do what you want/need. Want to make your code a bit faster? Write Python with type annotations. Want to call a C library? Just import the header, and then use it from a function.

Pybind11 is also great, but quite different in aims - I feel like it's more like a project for C++ programmers wanting to expose functionality to Python.

jokoon|3 years ago

Any benchmarks for type annotations?

I already wrote a few patch for pysfml, which is written in cython, it was a bit awkward, and now I'm asking myself if cython is really the right tool to write bindings, compared to cpython, for example.

machinekob|3 years ago

Python with type annotations isnt faster using python runtime.

But some packages can utilize it for higher performance but most of the time it'll be slower cause you need to parse extra information if you want to reuse it in pure python.

erwincoumans|3 years ago

I would recommend considering using NanoBind, the follow up of PyBind11 by the same author (Wensel Jakob), and move as much performance critical code to C or C++. https://github.com/wjakob/nanobind

If you really care about performance called from Python, consider something like NVIDIA Warp (Preview). Warp jits and runs your code on CUDA or CPU. Although Warp targets physics simulation, geometry processing, and procedural animation, it can be used for other tasks as well. https://github.com/NVIDIA/warp

Google Jax is another option, jitting and vectorizing code for TPU, GPU or CPU. https://github.com/google/jax

logicchains|3 years ago

>I would recommend considering using NanoBind, the follow up of PyBind11 by the same author (Wensel Jakob), and move as much performance critical code to C or C++

Why would you recommend that? It's all way more effort than just writing Cython, especially in a Jupyter Notebook. And Cython code can be just as fast as C/C++ code unless you're doing something really fancy. It's a bunch of work for no benefit.

>Warp jits and runs your code on CUDA or CPU

If someone's writing Cython it's probably because they found something that couldn't be done efficiently in Numpy because it was sequential, not easily vectorisable. Such code is going to get zero benefit from Cuda or running on the GPU.

In general, all your jitted code is not going to be as fast as code compiled with an ahead-of-time compiler like the C compiler that Cython uses. Moreover if you use a JIT then it makes your code a pain in the ass to embed in a C/C++ application, unlike Cython code.

jcelerier|3 years ago

if the object you wanna bind fits into the mold of "an algorithm with inputs and outputs, and some helper methods" I've got automatic binding of a limited set of C++ features working in https://github.com/celtera/avendish ; for now I've been using pybind11 but I guess everything I need is supported by nanobind so maybe i'll do the port...

cb321|3 years ago

cython --annotate is an ok way to learn the whys & whereabouts of the rather hairy CPython API. That gives you an HTML page you can click on to expand your python code into equivalent-ish C API calls. Darker yellow means more calls, too. So, it's not a terrible start to do static analysis to guide optimization, but a combination score (with a run-time profile) would be even better.

I believe there was a time very early on (like 2003) when there was discussion about maybe including Pyrex in CPython proper to get a more Common-Lisp like gradually typed system. (I mostly recall some comment of Greg's along the lines of being intimidated by such. I'm not sure how seriously the idea was entertained by PyCore.)

pjmlp|3 years ago

While it is nice that this option is available, it would be much better if Python itself would embrance the necessary runtime capabilties to not have to rely on it.

fname11|3 years ago

This is not going to happen. GvR has successfully ignored Cython and PyPy for decades and has attached himself to a JIT project at Microsoft (has anything emerged?).

CPython is in the hands of not really productive bigcorp representatives who care about large legacy code bases. My guess is that CPython will be largely the same in 10 years, with the usual widely hyped initiatives that go nowhere ("need for speed etc.").

f311a|3 years ago

To write fast Cython, you basically need to write in C and control everything including Python API calls. No runtime will help with this.

chaxor|3 years ago

Don't count on it - switch to Julia instead.

victoryhb|3 years ago

I tried to learn Cython last year, but was thwarted by two issues: (1) its syntax was too ugly for my taste and support for the pure Python mode was immature; (2) performance bottlenecks were opaque and hard to profile (at least for beginners). I ended up picking up Nim, a language with Python-like syntax and C-like performance, and was productive within hours (literally). I never looked back.

Bostonian|3 years ago

Is the 2015 O'Reilly book on Cython by Kurt Smith still a good starting point to learn about it, or is it outdated?

c-fe|3 years ago

I have heard about Cython before but I have never actually used it. I have however used Numpy, Scipy and Numba. Are there any reasons to also consider Cython in combination with those other libraries? E.g. in which cases would Cython be considerably better than Numpy or Numba? My workload consists mostly of data science and statistics, running models and simulations.

dagw|3 years ago

Cython works great in conjunction with Numpy arrays and you can easily call numpy and scipy methods from within Cython. The big win comes when you have to do some operation to a numpy array that doesn't have a 'fast' path within numpy. If you ever find yourself in a situation where you have to loop over or apply any sort of custom operation to every element in a numpy array then Cython can be a huge win, especially since Cython also makes it possible to parallelise those loops.

The other place it shines is if you ever need to loop over an array of data that cannot easily be represented as numpy arrays, like strings or more complex structs. Here you can get significant speedups compared to python.

The third use of Cython I really like is with C and C++ interop. Sure there are lots of ways of calling C code from Python, but to me Cython is probably the quickest and cleanest.

Compared to Numba, it's harder to say. Numba, when it works, is easily as fast as Cython. However I find Numba hard to reason about and it's still a bit of a black box as to when and why it does and doesn't work. The nice thing about Cython is that it is pretty simple so you can easily reason about what it will do your code and how it will perform. It's been a long time since Cython 'surprised' me by performing much better or worse than I expected.

If you want to see Cython in action, take a look at the source code of scikit-image or scikit-learn. They implement many of their core algorithms in Cython

rich_sasha|3 years ago

Numpy and Scipy do the heavy lifting in fast compiled C / Fortran, but if you write a for-loop doing these things, it will still be (comparatively) slow.

Numba is a JIT, and only covers some of Numpy. I'd say it's amazing at how well it works, but it "only" covers certain aspects of the language. It's also a bit of an all-or-nothing - if it doesn't cover a certain class of syntax, it just won't JIT.

Cython is ahead-of-time compiled, and much more comprehensive. It turns Python, effectively, into C, and compiles it as a Python extension. The possible scope is thus much greater, and although Cython comes with built-in support for Numpy, it is much more broad in principle.

So... it's a very different set of trade-offs. Like with Numba, out of the box, with no changes, you will typically see a significant improvement (what's significant? From experience about 2x). You have much more scope for tweaking your code to speed things up - move some of the execution to C, disable bounds checking, outright call C libraries, etc. It comes with a suite of tools for analysing performance bottlenecks. It used to come with a lot of special syntax, which nowadays is done with annotations and decorators - much neater IMO. And of course, no run-time compilation delay, it's moved to, well, compilation time.

nicoco|3 years ago

Numba is better in my opinion for the use case you describe, less hassle.

However, (I think) cython is superior when:

- you want to distribute (eg as a pypi package) your code

- you want to interface with C/C++ code libs

I found out I almost never have to do this and did not touch cython since I started using numba.

gotaquestion|3 years ago

I like cython, but I think it pigeon-holes developers: i've seen hardware modules written in Cython, when they could easily switch to C++ and provide a library that could be used as an FFI in any language, but instead locked themselves (and users) into the narrow world of Python.

Is there a way to convert a Cython module(s) to C++, or at least a .o file? They are so dang close.

blindseer|3 years ago

I wish Cython was a more popular option than choosing Julia or Go. Cython is great and you can get some real performance out of it.

The only drawback is that a Cython module still loads the CPython interpreter, so I personally prefer writing performance critical code in Rust instead. Writing in Julia has the same drawbacks of not being embeddable that writing in Cython does.

Julia has multiple dispatch and may seem more appealing but at scale it is a very slow language to develop in. And for scripts it takes FOREVER (try loading Plots, CSV, DataFrames, Makie etc every time you restart. It’s genuinely insane that that’s the norm.)

If the whole Python ecosystem was in Cython (i.e. numpy, scipy, etc) I’d never use another backend language again.

jokoon|3 years ago

Question: I found python "bindings" for SFML, written in cython, and patched them a bit.

I guess Cython is not really made to write bindings, but is it easier to write bindings with cython or cpython?

Galanwe|3 years ago

As someone who has been writing python bindings regularly for 10 years:

Writing bindings in Cython is much, much faster in terms of development time. It fits nicely and unintrusively in an already python packaged library. You can gently add some C functions or call C libraries in minutes.

You won't have a full control of what's happening though. Just have a look at the generated code and you'll see the mess of indirections that are generated.

Cython bindings become limited when you have to build more complex stuff though, going deeper than just calling some C functions. The typical case is when you have to actually handle the lifetime and borrowing of C native objects.

At that point, CPython will be the way to go, but it's much more code, and very error prone: you have to manually keep track of reference counting.

kubb|3 years ago

and i still have no idea what i could use it for...

dagw|3 years ago

It's great for speeding up 'hot' functions in your python code and makes it easy to call C libraries from python.

nurbl|3 years ago

It's easy to drop in Cython in an existing project where you need some performance, and start gradually "cythonizing" modules from the inside out. The rest of the code does not need to care.

With a bit of care (and benchmarking) you can get very respectable speed. The main drawback is that the further you go, the more C knowledge you need in order to not blast your own feet off.

If you're just after a bit more performance in general, a drop in solution like pypy might be enough.

ergo14|3 years ago

We speed up our ML code 40 times using it.

hansor|3 years ago

We had to parse dozeon of 20GB files daily with super complex structure and not in linear structure. With Cython (finally we migrated to Pypy) we gained around 20-60x speedup.

baq|3 years ago

it's C with Python syntax and syntactic sugar for Python objects on C level, including refcounting, which is the hard part.

if you successfully use numba, probably nothing that you couldn't already do.

if you want something that lives much closer to C, it's perfect.