Live data from Hacker News

Zero-cost futures in Rust

aturon.github.io

241–250 of 348 posts

Re: Zero-cost futures in Rust

#241

This is cute. This is clever. Whether or not it's too clever time will tell. A year ago, I noted that Rust was starting out at roughly the cruft level C++ took 20 years to reach. Rust is now well beyond that. All this "futures" stuff strongly favors the main path over any other paths. You can't loop, retry, or easily branch on an error, other than bailing out. It's really a weird syntax for describing a limited type…

> All this "futures" stuff strongly favors the main path over any other paths. You can't loop, retry, or easily branch on an error, other than bailing out.

You can do all of that.

Re: Zero-cost futures in Rust

#242

This is cute. This is clever. Whether or not it's too clever time will tell. A year ago, I noted that Rust was starting out at roughly the cruft level C++ took 20 years to reach. Rust is now well beyond that. All this "futures" stuff strongly favors the main path over any other paths. You can't loop, retry, or easily branch on an error, other than bailing out. It's really a weird syntax for describing a limited type…

How does futures count as cruft? It's a pure library. This is like saying GObject is cruft in C. It is a library that some folks don't like (like most libraries), but it is not part of the language and nobody is forced to use it in their code.

Why do you think Rust has cruft anyway? It has a lot of typesystem features, yes, but this is no different from languages like Haskell. These features work together nicely and are useful. C++ has lots of features which for better or for worse have been hacked in to the language (can't be made an organic part of the language because backcompat). This is not the case with Rust (or D, which is to me a cruft-less organically-designed C++)

Re: Zero-cost futures in Rust

#243

Earlier quoted context omitted.

What I/O doesn't go through the kernel?

For the example if you are using kernel bypass of the network stack, which is increasingly common in high throughput/low latency applications.

If you're going to bypass the kernel network stack for performance, you're definitely not going to write the rest of your code in go. The garbage collector, goroutine scheduler, and conservative compile time optimizations will totally undermine the end goal.

If you're in that world, you're using C, C++, or That if you're feeling dangerous.

Re: Zero-cost futures in Rust

#244
post #84

As mentioned in the post, given Rust wants to operate in the same space as C, this approach makes sense. However from a higher level, building more complex concurrent systems, dealing with futures/deferred-s/promises and/or a central select/epoll/kqueue reactor loop gets daunting and doesn't mix with complex business rules. Deferred based approach has been a round for many years. I experienced it by using Twisted (Py…

Dealing with futures is fairly straightforward if the language offers some syntactic sugar for continuations (such as C#'s async/await that has been spreading around for some time now). Why doesn't it mix well with complex business rules?

I'm not sure I would go as far as saying they can't. I'm quite comfortable with F#'s async computation expression and like them a lot.

You get a strange sense however when playing with Hopac (which btw has an analog sugar to F#'s async which works just fine) and going through the content in Reppy's book that the model is strictly more composable. I'd invite you to try it although I don't have a sense for the C# combinators.

Re: Zero-cost futures in Rust

#245

Earlier quoted context omitted.

Aren't generic types with one associated type isomorphic to 'normal' generic types? In that sense, it is still odd.

Not exactly. A given type can have infinite implementations of iterator (by implementing for different A) but only one impl for iterator

I don't think I get that without an example. Do you know of any simple examples?

Re: Zero-cost futures in Rust

#246
post #153

Earlier quoted context omitted.

> You use green threads instead of native threads because native threads have space overhead, not because they have time overhead. The main overhead of a thread, green or native, is the stack. The size of the stack is independent of whether you use native or green threads. Go's small stacks are actually made possible by its GC, not its choice of 1:1 or M:N. In musl, for example, you can have 2KB stacks [1] with 1:1.…

> The kernel scheduler has a much more global picture of the system compared to userland. In most of the comparisons I've seen (usually for Erlang), worst-case latency was the important factor, so interaction with the kernel scheduler was avoided as much as possible. In the Erlang runtime, you can pass a switch to cause the userland scheduler-threads to each get bound to a particular processor core, and to cause the…

If the kernel scheduler completely hands control of the core over to the program, doesn't that mean you can only run one or two programs on the entire machine at once without running out of cores? Surely the kernel still schedules other threads on that core too.

Re: Zero-cost futures in Rust

#247

Earlier quoted context omitted.

Yep, that's why I'm asking about the use-cases in the grandparent comment.

As an example, many real-time systems are often a giant ball of messy asynchronous code and state machines. Futures can help with that, although lately I have found that somtimes the best, cleanest, way to implement a state machine is to make it explicit.

How much do you attribute that to the benefit of creating a high barrier to entry for modifying that code? Could this be summarized as: code that inexperienced devs can't understand, stays performant because they can't figure out how to change it?

Re: Zero-cost futures in Rust

#248

Earlier quoted context omitted.

I haven't seen a benchmark of huge numbers of native threads vs. a userland scheduler, but I have a hard time imagining that a userland scheduler will beat the kernel's scheduler. The kernel scheduler has a much more global picture of the system compared to userland. Doesn't using kernel threads imply lots of context switches? Doesn't that tend to be expensive in terms of time on modern architectures?

> Doesn't using kernel threads imply lots of context switches? No, it's actually fewer context switches. That's because each I/O completion event goes straight from the kernel to the code that was waiting on it (1 context switch), not from the kernel to the userland dispatcher to the code that was waiting on it (2 context switches).

The real cost of a true "context switch" is the transition from user level to kernel level, which takes thousands of cycles. This cost isn't incurred on a userland context switch, so those costs aren't comparable.

Re: Zero-cost futures in Rust

#249

I'm genuinely interested in knowing what the problem is with an event loop using epoll and a threadpool for IO that blocks but epoll can't poll. I've used proprietary event loops at 2 giant companies, libuv with C, asio with cpp and nodes async, and the async IO was never the problem in terms of performance or complexity. What is the problem that's trying to be solved?

The problem being solved is better UX (in this case, developer experience). It is an event loop using epoll and a threadpool, just in a more palatable (and composable) interface, without much overhead.

Re: Zero-cost futures in Rust

#250

This is cute. This is clever. Whether or not it's too clever time will tell. A year ago, I noted that Rust was starting out at roughly the cruft level C++ took 20 years to reach. Rust is now well beyond that. All this "futures" stuff strongly favors the main path over any other paths. You can't loop, retry, or easily branch on an error, other than bailing out. It's really a weird syntax for describing a limited type…

How does futures count as cruft? It's a pure library. This is like saying GObject is cruft in C. It is a library that some folks don't like (like most libraries), but it is not part of the language and nobody is forced to use it in their code. Why do you think Rust has cruft anyway? It has a lot of typesystem features, yes, but this is no different from languages like Haskell. These features work together nicely and…

Yes, it's a pure library. But this sort of thing is becoming standard for Rust. If your code isn't full of "foo.and_then(|x| ...)" it's uncool. This isn't "functional"; these functions have major side effects.

The bothersome thing is that the control structures of the language are hidden under object-specific functions. "Things really start getting interesting with futures when you combine them. There are endless ways of doing so." I'd rather have "there's only one way to do it", as in Python, rather than "endless ways of doing so". That usually leads to code that's hard to read and debug. As in "how did control get there?". At least in traditional code, you can see control flow easily. Adding an user-definable level of abstraction hides that.

Post reply on HN