News for hackers. Stuff that matters.
Re:Writing a small ray tracer in Rust and Zig by OskarS on Tuesday July 02, 2019 @07:43AM (#20334058)
I will say, the one example they have there which is sort-of analogous to "render each pixel of this image in parallel" is the "draw a julia set" one [0], and it's a very bad way of convincing a C/C++ programmer that Rust is good at this sort of thing. Even if the "loop over all rows in the main thread, adding to the pool a lambda that loops over each column" is somehow optimized in a good data-parallel way (I doubt it compares favorably performance-wise with "#pragma omp parallel for"), the lambdas then push each finished pixel into a channel along with their coordinates. The main thread then has to literally loop through every pixel and read from the channel for each and every one.

The natural way to do that in C/C++ is to just write the pixel to the bitmap in each thread. There are no race conditions here (everything is embarassingly parallel), just write the resulting pixel to the bitmap and be done with it. The only reason to have that channel with all that overhead (and that final synchronization on the main thread) is to satisfy the borrow checker, which is just silly in this case. It adds a tremendous amount of overhead just to make it idiomatic Rust.

It's true that you can do it the "C++ way" in Rust using unsafe and raw pointers (and there's probably crates that can do the "parallel for" in a way that compares well with OpenMP), but as a graphics programmer who's done a lot of this sort of thing, that piece of code made a very bad first impression of Rust as a high-performance language.

EDIT: also, the description is wrong. It says: "ThreadPool::execute receives each pixel as a separate job". No it doesn't, it receives each scanline as a separate job. It might be better if the pool had each pixel as a separate job, but that's not what the code is doing.

[0]: https://rust-lang-nursery.github.io/rust-cookbook/concurrenc...

Re:Writing a small ray tracer in Rust and Zig by gmueckl on Tuesday July 02, 2019 @08:37AM (#20334396)
To me, this somehow says that most truely interesting problems can only be solved efficiently in Rust using unsafe. Granted, my definition of interesting may be a bit limited, but my initial takeaway here is that Rusts safety story is much more limited than its proponents claim.
Re:Writing a small ray tracer in Rust and Zig by pcwalton on Tuesday July 02, 2019 @12:26PM (#20336670)
> To me, this somehow says that most truely interesting problems can only be solved efficiently in Rust using unsafe.

Even Vec is implemented with unsafe code under the hood. Rust isn't about not using unsafe code anywhere: it's about encapsulating that unsafe code in reusable abstractions that can be easily audited. This is how essentially all languages work to begin with: unless you're using CompCert, the compiler itself is not proven correct, and so the compiler's code generator is "unsafe".

Here's an example of how rav1e, an AV1 encoder in Rust, builds safe abstractions out of unsafe primitives in order to solve a similar problem: https://blog.rom1v.com/2019/04/implementing-tile-encoding-in...

Re:Writing a small ray tracer in Rust and Zig by gmueckl on Tuesday July 02, 2019 @12:55PM (#20336975)
Wait, so how exactly is Rust better than C++ again? If I need to bring my own unsafe code to the party, where is the gain? Especially, if - in your words - "This is how essentially all languages work to begin with". I can build "safe" abstractions in any other language, too, can I not?
Re:Writing a small ray tracer in Rust and Zig by pcwalton on Tuesday July 02, 2019 @02:19PM (#20337875)
No, you can't build safe abstractions in C++. The language lacks the ability to enforce memory safety. Every abstraction you can come up with will have some way to subvert it. In Rust, the abstractions can't be broken without using unsafe, which application logic should never use.

This isn't just a theoretical distinction. Empirically, Rust programs have far fewer memory safety problems than C++ programs do.

Re:Writing a small ray tracer in Rust and Zig by CUViper on Tuesday July 02, 2019 @01:04PM (#20337081)
In other languages, nothing ensures that those safe abstractions are actually used in safe ways. You can keep a dangling reference to a C++ vector, but Rust will make sure your references are valid, and you can only escape that with raw pointers in an unsafe block.
Re:Writing a small ray tracer in Rust and Zig by unrealhoang on Tuesday July 02, 2019 @01:39PM (#20337459)
C++ doesn't have the tool to do so. Just like you can build abstraction for raw data in any language, but only the compiler in static typed language will scream at you at compile time if you use it the wrong way and dynamic language will just believe you will do the right thing.
Re:Writing a small ray tracer in Rust and Zig by eridius on Tuesday July 02, 2019 @02:11PM (#20337801)
In general you don't need to bring your own unsafe code to the party. The standard library contains most of the unsafe code you'll need to use in your normal code, and a handful of well-supported crates (like rayon) provide the more advanced utilities that the standard library doesn't. In most cases you're only writing `unsafe` if you're interacting with C.

And when you do decide you need to use `unsafe` for a non-FFI purpose, Rust provides the tooling to explicitly define the abstraction barrier such that clients of your code don't have to care (or even know) that you're using unsafe internally.

Re:Writing a small ray tracer in Rust and Zig by steveklabnik on Tuesday July 02, 2019 @10:14AM (#20335324)
To reply to both you and your parent at once, yes, the reason this is in the nursery is that it's not a complete resource yet. I agree that this particular example is bad; it's showing the right pattern for the wrong example.

The right way is to use rayon, which is similar to OpenMP in this sense. Each thread would get a pointer to the chunk of the buffer it's operating on. You don't need to write any unsafe code to do this.

Re:Writing a small ray tracer in Rust and Zig by OskarS on Tuesday July 02, 2019 @10:33AM (#20335539)
It's good to hear that there's an idiomatic Rust way of doing this that doesn't require unsafe but is still performant. I figured there was, but to an outsider it was not obvious how.

This is not actually the first time I've seen this example code. I was wondering how Rust solved this issue (parallel rendering into a single framebuffer) in a way that satisfied the borrow checker, and came across this example. It was a bit disheartening. Rust seems like an excellent language with boundless potential, but as I said, this particular example makes for a very bad first impression. It is also not obvious at all that this is part of the "nursery" and is not an official Rust document (the "Rust Cookbook" makes it seem more polished than maybe it is).

Re:Writing a small ray tracer in Rust and Zig by steveklabnik on Tuesday July 02, 2019 @10:39AM (#20335595)
> It's good to hear that there's an idiomatic Rust way of doing this that doesn't require unsafe but is still performant. I figured there was, but to an outsider it was not obvious how.

Yeah, I mean, the reddit thread way up this comment chain talks about how Rayon should have been used, but the discoverability issue is real.

> It is also not obvious at all that this is part of the "nursery" and is not an official Rust document (the "Rust Cookbook" makes it seem more polished than maybe it is).

Yep; it's in the URL but not everyone will see that. Like most things, this is basically an accident of history; there was a push to clean this project up and make it an official resource, but before that work was finished, all the contributors had life stuff happen and had to go do something else. So it's in this weird quasi-state where there's a ton of good in there, but also some bad. We'll get to it...

Re:Writing a small ray tracer in Rust and Zig by steveklabnik on Tuesday July 02, 2019 @12:27PM (#20336685)
Oh, someone on Reddit posted the rayon using code https://www.reddit.com/r/programming/comments/c7sgvw/writing...
Re:Writing a small ray tracer in Rust and Zig by pcwalton on Tuesday July 02, 2019 @12:27PM (#20336681)
Here's an article explaining how rav1e, an AV1 encoder aiming for production quality, solves this problem: https://blog.rom1v.com/2019/04/implementing-tile-encoding-in...