Live data from Hacker News

Asynchronous IO in Rust

medium.com

41–50 of 111 posts

Re: Asynchronous IO in Rust

#41
post #36
post #3

If you use threads, green or otherwise, you don't have to "implement" special code for composing things together, you get the full set of tools for composing code together, which includes, in passing, state machines, among all the other things it includes. This basically implements an Inner Platform Effect of an internal data-based language for concurrency that the language interprets, which will A: forever be weaker…

Isn't this a rehash of the C10K problem[1] from a decade ago? That was pretty much resolved in favour of single-threading and asynchronous IO, with Nginx and Node.js replacing Apache and Ruby as the platforms that the cool kids use. So, if threads are the way to go today, what has changed in the last 10 years to turn the conventional wisdom on it's head? 64-bit processors and servers with more memory? Hypervisors/con…

No, backwards: the C10k techniques are the solution to the problem "how do I achieve my performance and scaling goals given the characteristics of the OS, languages, tools available to me today?". The current thread (sic) is asking the question "if we can change the language, tools (perhaps the OS too), what's the best approach?".

And: I have to counterbalance the assertion that Node.js is in any way good for anything besides "I need to code in JS, but not in the browser". I'd rather use VAX assembler and the $QIO syscall, typing on a VT100.

Re: Asynchronous IO in Rust

#42
post #4

Earlier quoted context omitted.

> What's so wrong with Rust threads, excepting perhaps them being heavyweight? (Far better to solve that problem directly.) Nothing. If threads work fine, use them! That's what most Rust network apps do, and they work fine and run fast. A modern Linux kernel is very good at making 1:1 threading fast these days. > And having written network servers with pretty much every abstraction so much as mentioned in the article…

Most of my work involves kernel programming (device drivers for hardware or virtualisation companies etc.); almost all of the rest of it is writing networking code (custom protocol implementations). So my reasons for evaluating[1] Rust are that I think C and C++ are pretty awful languages for writing code that's as security and reliability critical as the code I touch on a day to day basis, while memory-managed langu…

I think you should take a look at C#'s async/await infrastructure.

I am also from a low-level C background and I think this is the approach I would like to see in Rust.

It can be implemented in a way that would be safe to run in kernel space and overall provides a pretty nice programming model. It can also be very performant if it's integrated into the compiler.

Re: Asynchronous IO in Rust

#43

Earlier quoted context omitted.

I'm confused. To me, green threads are just an implementation detail. The fact that green threading is being used shouldn't leak into the interface. To take Go for an example, you could perfectly well write a conforming implementation of Go that used 1:1 native threading: it would just have different performance characteristics and things like LockOSThread() would become a no-op. Could you elaborate on what you consi…

The interface is different because if you use a green thread within a GC'd language, you can do anything -- change anything, interact with anything -- and nothing will crash. No locking involved, and no hidden locking under the hood. It's not meant to be a performance boost, but a way of writing code where "might this crash?" is a question you're never bothered to ask. It's wonderfully freeing. Not true of native thr…

We're talking pretty explicitly about Rust, which doesn't have that problem.

Re: Asynchronous IO in Rust

#44
post #42

Earlier quoted context omitted.

Most of my work involves kernel programming (device drivers for hardware or virtualisation companies etc.); almost all of the rest of it is writing networking code (custom protocol implementations). So my reasons for evaluating[1] Rust are that I think C and C++ are pretty awful languages for writing code that's as security and reliability critical as the code I touch on a day to day basis, while memory-managed langu…

I think you should take a look at C#'s async/await infrastructure. I am also from a low-level C background and I think this is the approach I would like to see in Rust. It can be implemented in a way that would be safe to run in kernel space and overall provides a pretty nice programming model. It can also be very performant if it's integrated into the compiler.

We have a ticket open: https://github.com/rust-lang/rfcs/issues/388

Re: Asynchronous IO in Rust

#45
post #15

Earlier quoted context omitted.

One nice thing about Rust is how well suited it can be for embedded use. It is something like a smaller safer easier C++. For embedded you need to bound resources. Small network appliances are a good candidate for async IO. Many threads and stacks with a lot of dynamic allocation are not a good fit for a resource constrained device.

There are still other blockers on embedded though. LLVM doesn't target every architecture, and still no allocator API or OOM handling.

The dynamically-allocating portions of the stdlib may panic on OOM, but in an embedded context you're not even linking that code into your program. And you're free to provide an alternative stdlib that bubbles up OOM for those rare occasions where you want to dynamically allocate and you want to be able to do something sane in the face of OOM and you're on a platform that doesn't overcommit.

Re: Asynchronous IO in Rust

#46
post #40

I think a lot of folks think of Network IO when they say Asynchronous IO. That's only half the story, unless you're just building proxies and caches you have to deal with Disk IO at some point in time. And, async disk IO is horrible in every OS / language.

Care to explain why async disk IO is horrible?

AFAIK, the kernel APIs only deal with abstract handles and descriptors - they aren't written specifically for disk IO or network IO. And C#'s async/await and BeginXXX also work fine with all kinds of IO.

Re: Asynchronous IO in Rust

#47
post #45

Earlier quoted context omitted.

There are still other blockers on embedded though. LLVM doesn't target every architecture, and still no allocator API or OOM handling.

The dynamically-allocating portions of the stdlib may panic on OOM, but in an embedded context you're not even linking that code into your program. And you're free to provide an alternative stdlib that bubbles up OOM for those rare occasions where you want to dynamically allocate and you want to be able to do something sane in the face of OOM and you're on a platform that doesn't overcommit.

Minorish point: a true OOM won't panic, it'll abort the program completely. Some APIs may identify that the requested amount of memory is impossible (would overflow) and panic instead, though.

Aborting once the allocator has actually been invoked is important for perf and exception safety, though we have briefly mused allowing it to panic: https://github.com/rust-lang/rust/issues/26951

Re: Asynchronous IO in Rust

#48

Earlier quoted context omitted.

> Green threads didn't provide performance benefits over native threads in Rust. That's why they were removed. This seems wrong. This shouldn't be the point of green threads -- green threads aren't a "faster" alternative to native threads. How would that work? How could it be the case that virtual threads implemented in user space are faster than native threads provided by the OS? I don't think anyone expects that to…

I'm confused. To me, green threads are just an implementation detail. The fact that green threading is being used shouldn't leak into the interface. To take Go for an example, you could perfectly well write a conforming implementation of Go that used 1:1 native threading: it would just have different performance characteristics and things like LockOSThread() would become a no-op. Could you elaborate on what you consi…

> To me, green threads are just an implementation detail. The fact that green threading is being used shouldn't leak into the interface.

I think that mentality, which I supported, may be what ruined green threads for Rust. Perhaps the enemy was the perfect of the good. On the other hand, maybe not having to worry about differences is the better benefit. I would rather be slower-but-acceptably-fast than have to think about 1:1 vs M:N threading in the case that they are not interchangeable.

On the third hand, it could be that Rust is too close to the metal for green threads to be of any significant benefit. If that's the case, Rust ought to trounce all the M:N implementations, subject to reasonable limits on spawn rate, memory pressure and inter-thread communication. Does that sound right?

Incidentally, I've never seen a cooperative threading implementation that didn't have a yield call of some kind available, and you can usually jam any of them up by writing an infinite computation-only loop, so even in the langauges where the scheduler is automatically invoked, correct 1:1 code can deadlock in the M:N scenario. State machines can too, but a trivial example, translated, might read something like the following:

    for(;;);
    exit(EXIT_SUCCESS);
I've seen code like this written by complete newbies, but threading constructs can hide that relationship even from experts. In parallel code it isn't a sequential relationship, but it is with cooperative threads. I guess this is all fairly pedantic (such a minor detail, mostly affecting only poorly-written programs), but in the end, one of: yield(), sched(), sync(), etc. does show up in practically all of the cooperative threading interfaces.

Re: Asynchronous IO in Rust

#49
post #45

Earlier quoted context omitted.

There are still other blockers on embedded though. LLVM doesn't target every architecture, and still no allocator API or OOM handling.

The dynamically-allocating portions of the stdlib may panic on OOM, but in an embedded context you're not even linking that code into your program. And you're free to provide an alternative stdlib that bubbles up OOM for those rare occasions where you want to dynamically allocate and you want to be able to do something sane in the face of OOM and you're on a platform that doesn't overcommit.

OOM is an abort, not a panic (contrary to the official docs, interestingly)

> you're free to provide an alternative stdlib

But like... should you have to?

> for those rare occasions

In kernel programming, allocation failures are common and handling them is essential. To quote my (very talented) classmate, who actually wrote part of a kernel in Rust:

"The only really major issue is with how allocation failure works, which makes rust a (very) poor choice for real kernel development"

https://www.reddit.com/r/rust/comments/341v3n/cs_honors_thes...

Re: Asynchronous IO in Rust

#50

Earlier quoted context omitted.

Rust's green threading was... unusual. It attempted to abstract green and native threads into a single API, which lead to a lot of unnecessary overhead: https://github.com/rust-lang/rfcs/blob/0806be4f282144cfcd55b... Sadly, that proposal also removed concurrent IO from the standard library, and it hasn't been replaced.

It may not be replaced in the standard library, but mio exists and is what most people use for non-blocking stuff.

1. Stackless coroutines will probably require help from the compiler team (hint hint). It'll be worth it! Think web frameworks with Nginx performance and Rust memory safety.

2. Documentation, stability, portability, quality. I'll keep banging that drum until there's a standard. :)

3. The Mio API is subjectively weird, but I might be missing something.

Post reply on HN