Live data from Hacker News

Calling Rust from Python using PyO3

saidvandeklundert.net

21–30 of 51 posts

Re: Calling Rust from Python using PyO3

#21
Check out apache arrow in rust for transferring large amounts data between rust and python. With it you can get zero copy transfers between the languages. Afaik there is some performance penalty involved when converting python types to native rust types.

It used to be hard to do such transfers between rust and python using arrow but from v3 or v4, arrow implementation in rust started supporting the c data interface. Creating the array in rust and sending it to python might involve leaking a boxed object though

Check this out if you want to see how https://github.com/jhoekx/python-rust-arrow-interop-example/...

Re: Calling Rust from Python using PyO3

#22
post #21

Check out apache arrow in rust for transferring large amounts data between rust and python. With it you can get zero copy transfers between the languages. Afaik there is some performance penalty involved when converting python types to native rust types. It used to be hard to do such transfers between rust and python using arrow but from v3 or v4, arrow implementation in rust started supporting the c data interface.…

i was using rust numpy for this, i wonder how much faster this is and if it supports passing arrays of strings

Re: Calling Rust from Python using PyO3

#24
I recently wanted to use some rust crates from Python and decided to give PyO3 a go and I must say it works really well.

Took about one evening to plug it all together and get it running. The guide at pyo3.rs was really helpful and maturin to build binary packages just works. You pass in python types and they arrive as rust-native types. Makes writing code feel very native.

The result: https://github.com/Grollicus/pyttfwrap takes a string and splits it as it would wrap when rendered with a given TTF font. Most of the code is about keeping a reference to the loaded font as that's an expensive operation.

Was some great fun and I'm sure I'll use it some more.

Re: Calling Rust from Python using PyO3

#25
post #10
post #2

I hope someone creates a rule set for Bazel to automate this stuff. This seems like a really nice way to start rewriting performance critical code in a safe language!

I’ve been having difficulty recently trying to get bazel and rust to work together nicely. It seems like cargo does a lot of heavy lifting w.r.t. dependencies which Bazel does not like. Do you have to vendor your dependencies- and your dependencies dependencies. Ad infinitum. There is cargo-raze which helps, but only if you’re making a rust library: not if you’re making a binary. So maybe it works for this case.

Not disagreeing that cargo-raze in bazel is awkward, but just wanted to add:

Cargo raze should let you consume libraries you've imported in a rust_binary target, if that's what you're talking about. It's also possible, but slightly more annoying, to vendor the dependency tree if you need to rely on pulling from a local mirror.

I've also used it to import cargo binaries (i.e wasm-bindgen-cli) into a Bazel workspace -- it just makes the resulting target something like @raze_some_bin//:bin

Re: Calling Rust from Python using PyO3

#26
post #2

I hope someone creates a rule set for Bazel to automate this stuff. This seems like a really nice way to start rewriting performance critical code in a safe language!

I've been using this macro in my personal projects repo: https://pastebin.com/raw/atNtPgwv

The three big gotchas with this are:

- You need to name the rule the same as the module you've exported in Rust

- It creates a copy to get the naming right. You could write an actual rule instead of a macro that just makes a symlink with the right name for Python to pick it up.

- Since the macro just exposes a genrule and isn't a PyInfo provider, you need to add it in the data of the py_library/binary you intend to use it in. Again, could be fixed by an actual rule impl.

Re: Calling Rust from Python using PyO3

#27
We've been using PyO3 and Maturin at Spring for a while now, and happily. The smooth Python interop means we can call out to Rust without much pain for performance-critical codepaths. But the other side-effect is that we can use Rust across the org more broadly, even when Python interop isn't a consideration -- e.g., for isolated services, or applications that need to compile to Windows, or whatever else -- since we're building up the cultural knowledge and shared libraries to do so.

Re: Calling Rust from Python using PyO3

#28
post #22
post #21

Check out apache arrow in rust for transferring large amounts data between rust and python. With it you can get zero copy transfers between the languages. Afaik there is some performance penalty involved when converting python types to native rust types. It used to be hard to do such transfers between rust and python using arrow but from v3 or v4, arrow implementation in rust started supporting the c data interface.…

i was using rust numpy for this, i wonder how much faster this is and if it supports passing arrays of strings

Yup. It supports arrays of strings.

https://docs.rs/arrow/6.2.0/arrow/array/type.LargeStringArra...

As for performance, YMMV but I think it could be faster since storing a list of strings as a numpy array would involve padding. Arrow arrays can get away without padding

Re: Calling Rust from Python using PyO3

#29
post #13

This is smart thinking. Python is the world's best glue language and Rust is on track to become the world's best compiled, safe language. It makes sense to combine the two and replace C in this.

While Python's bindings in other languages are great, and Rust has amazing features regarding memory safety, I think saying they are the best in their area is a bit too much. For compiled languages: Rust is the best when you care about memory safety. C is the best when you care about performance/simplicity/portability. C++ is the best when you care about modularity, Assembly is the best when you care about lowlevel s…

Other people have pushed back about safety, but I want to push back on performance.

Here's the thing, presumably you agree that "It's fast except that it never works" isn't actually fast. So in practice your high performance C ends up compromised by the reality that it must work, at least often, which constrains what you are confident to actually write because you already know you can't write over-complicated code correctly.

Languages like Rust (and C++) enable you to write much more complicated software that you still understand well enough to debug it. An efficient filter that might be a single line of Rust or C++ may take dozens of lines of C, or else several macro invocations that add invisible overhead of lines that are constructed by the pre-processor unseen by the programmer, yet still taint the shared namespace and semantics. As a result, while the Rust or C++ programmer feels free to chain say, six filters the equivalent C looks monstrous and you recoil from it, even though that's the efficient way to solve the problem you had.

The intuition that if it looks simpler it's faster is often wrong, the reason Godbolt (Compiler Explorer) exists is that Matt Godbolt was concerned about whether the C++ for-each loop results in the same fast machine code as a manual loop, or whether you might pay a price for the nicer syntax. You don't, and Matt's continued exploration of this sort of issue, plus his generosity in sharing the result with the world is why the site is there now.

But of course the nicer iterator loop (and there are a lot of examples like this) encourages you to choose more complicated solutions which are faster, because total cognitive load isn't so great as it would be in a less expressive language. As a result even though you could in principle write an equally high performance C program, actual C programmers would not do that.

Now, machines don't fear complexity, so one of the interesting results of WUFFS is that they produce C code which no human would ever write, but which has all the properties they guaranteed (e.g. memory safety but lots more) in their small interest domain, by "simply" using tremendous amounts of complexity. The unexpected effect of this is that WUFFS-the-library is very fast: Since the only possible mistakes are programs that either don't do what is required or don't compile, WUFFS programmers are freed to focus on very fast tight code for the library. Again, you could in theory have written that code in C, but you wouldn't because you're human and you can't handle that.

Re: Calling Rust from Python using PyO3

#30
post #14
post #13

Earlier quoted context omitted.

While Python's bindings in other languages are great, and Rust has amazing features regarding memory safety, I think saying they are the best in their area is a bit too much. For compiled languages: Rust is the best when you care about memory safety. C is the best when you care about performance/simplicity/portability. C++ is the best when you care about modularity, Assembly is the best when you care about lowlevel s…

C, C++, and Assembly aren't safe, and Java and JS aren't good glue languages.

Implementing Rust's borrow checker as a C++ compile-time template metaprogramming exercise seems only a guru and a cloud-based compiler cluster out of reach.
Post reply on HN