Live data from Hacker News

Zero-cost futures in Rust

aturon.github.io

181–190 of 348 posts

Re: Zero-cost futures in Rust

#181

Earlier quoted context omitted.

> Being able to express your code in a sequential manor and still gain the performance offered by implicit fiber,goroutine,w/e scheduling is pretty awesome. You don't gain as much performance. On Linux, you don't actually gain that much if anything over 1:1 threading. Most of the benefits of goroutines actually comes from the small stacks, which don't have anything to do with M:N and 1:1 to begin with—they're a featu…

> Why would you write networking code in C in 2016, when there are better alternatives available (like this one)? Support for kernel bypass networking libraries like ibverbs, DPDK (has an old unmaintained Rust wrapper) and other IO kernel bypass libraries such as SPDK and IOAT. If Rust supported these libraries, I'd much prefer the future based Rust code to a massive event loop in C.

The article mentioned that the authors would love to help make futures-based wrappers for C libraries. You might ask if they could help with wrappers for ibverbs, DPDK, SPDK, and IOAT.

Re: Zero-cost futures in Rust

#182

I'm confused by .map(|row| { json::encode(row) }) .map(|val| some_new_value(val)) Over .map(json::encode) .map(some_new_value) Is the explicit extra layer of lambda generally prefered in Rust over just passing the functions?

It's just a style thing, some people prefer one way, some another. I personally prefer the latter. They compile to the exact same thing.

The makes sense. Do you know if Rust already has an idiomatic correct style?

Re: Zero-cost futures in Rust

#183

Earlier quoted context omitted.

The space overhead is significantly worse for native threading in the presence of many threads since each thread needs both a user and kernel stack. For M:N, there are N kernel stacks.

Fair enough, but kernel stacks are 8K. 10K user + kernel size is a far cry from the 2MB default pthread stack size people usually talk about when they talk about 1:1. I don't know of any benchmark comparing Go vs. a 1:1 implementation with 2K pthread stack sizes, but I would be surprised if the performance difference is large at all.

> Fair enough, but kernel stacks are 8K.

And getting even cheaper than that, with the effort to make kernel stacks use virtual memory. As I understand it, once kernel stacks use virtual memory, they'll start out at a single 4k page.

Re: Zero-cost futures in Rust

#184

Earlier quoted context omitted.

> Well, one advantage the Go runtime has is the green threads are cooperatively scheduled, so switches are a lot more lightweight. Switches occur on timeouts (which involve a round trip through the kernel), on I/O events (which also involve a round trip through the kernel), or on goroutine message passing. So in every case except goroutine message sends, the switches don't actually save you a trip through the kernel.

Except when the IO doesn't go though the kernel in the first place of course.

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

Re: Zero-cost futures in Rust

#185
post #180

Earlier quoted context omitted.

Arguing about whether a 30% difference is "significant" isn't really interesting.

You're talking about using a language where you have to manually manage the memory, is significantly harder to use than Go, have less built-in concurrent patterns, inferior standard library, so yes 30% seems a very small benefit. I didn't had look into the benchmark but my guess is that it's waiting on the I/O so any language with good concurrent model will have the same numbers. The benchmark would have been more in…

> You're talking about using a language where you have to manually manage the memory, is significantly harder to use than Go, have less built-in concurrent patterns, inferior standard library so yes 30% seems a very small as a benefit.

Naturally I disagree with all of those items, but I'm also equally uninterested in starting a Rust vs. Go war.

Re: Zero-cost futures in Rust

#186

Earlier quoted context omitted.

It's just a style thing, some people prefer one way, some another. I personally prefer the latter. They compile to the exact same thing.

The makes sense. Do you know if Rust already has an idiomatic correct style?

I don't think that there's ever been an explicit discussion about it. I'm not even sure how many people know the latter is possible, to be honest, it's a bit harder to learn about.

Re: Zero-cost futures in Rust

#187

Earlier quoted context omitted.

This is missing his point. "Increment" is called outside of its scope when the epoll triggers. If "counter" is stack allocated that would cause a segfault, so it must be heap allocated which is his point.

Well, they're two different points: closures in rust do not inherently have to heap allocate. But that also doesn't mean that they can _not_ be heap allocated either. And in this example, it's not even really the closures that allocate: it's still one allocation, regardless of the number of closures.

No. they are not two different points. You are artificially restricting the argument, and saying that some parts are a different question by introducing this new idea of "inherent nature" of a closure in rust : Some humans have legs, some do not. Does it mean that having legs is not an "inherent" part of the human experience?

So to go back to the argument, we are trying to compare using a coroutine base approach vs using a future/state machine + closure approach. My point was that because a coroutine allows one to enter and leave a stack frame without destroying it, it can lead to less allocation and therefore be more efficient in those cases (and let's not even talk about the cost of the activation/deactivation of the stack frame)

Re: Zero-cost futures in Rust

#188

Earlier quoted context omitted.

Well, they're two different points: closures in rust do not inherently have to heap allocate. But that also doesn't mean that they can _not_ be heap allocated either. And in this example, it's not even really the closures that allocate: it's still one allocation, regardless of the number of closures.

No. they are not two different points. You are artificially restricting the argument, and saying that some parts are a different question by introducing this new idea of "inherent nature" of a closure in rust : Some humans have legs, some do not. Does it mean that having legs is not an "inherent" part of the human experience? So to go back to the argument, we are trying to compare using a coroutine base approach vs u…

You don't have to destroy the "stack frame" (by which I assume you mean the state retained between blocking operations) every time you enter and leave. Why do you think you need to?

Re: Zero-cost futures in Rust

#189

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).

What if you have async system calls (e.g. FlexSC)?

Re: Zero-cost futures in Rust

#190

Earlier quoted context omitted.

In Rust it's frequently the case that slow compilations are dominated by generating and optimizing LLVM IR. This codegen step (generating LLVM IR) often takes awhile just because we're generating so much IR. Rust takes an approach with generic functions called monomorphization which means that we generate a new version of each function for each set of generics it's instantiated with. This means that a future of a Str…

Hm. I've heard arguments that C# or Java is slow for multiple reasons, but never because of the minuscule overhead of a virtual method dispatch when using objects behind interfaces (kinds similar to trait objects). It's interesting that this is seen as significant here. Are we dealing with much shorter timescales, or just being eager to optimise everything?

I assume at least part of it is that "zero-cost abstractions" is a fairly objective and boolean metric to calculate. "Is this performance impact significant enough to worry about?" would probably result in a lot more bikeshedding.
Post reply on HN