Live data from Hacker News

Zero-cost futures in Rust

aturon.github.io

141–150 of 348 posts

Re: Zero-cost futures in Rust

#141
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…

> So wondering if Rust provides any ability to add that kind of an N:M threading approach. Perhaps via an extension, macro or some other mechanism. I don't want M:N threading as Go implements it. It's a big loss of performance for marginal benefit over futures. In particular the libmill approach was tried in Rust and the results were far worse than 1:1. However, assuming this takes off I would like to see async/await…

> sugar over futures down the road to make it easier to write code that looks blocking but actually isn't.

Yes! That is basically what I am after.

Currently using Erlang so having to give up cheap isolated processes and message passing to do concurrency would be hard. But I understand that is a different level of abstraction as well (a VM, multi-machine clusters, etc vs almost raw C speed).

But in general bringing Rust and Erlang together seems like a swell idea. Both are focused on safety, which I like. Been keeping my eye on https://github.com/hansihe/Rustler

Re: Zero-cost futures in Rust

#142
post #122

Earlier quoted context omitted.

> I don't want M:N threading as Go implements it. As someone who writes code for enterpricey businesses doing a lot of I/O bound stuff, golang style M:N threading is a godsend over Java's standard library, and other common platforms in that space. 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. With futures, the…

> 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…

> On Linux, you don't actually gain that much if anything over 1:1 threading.

You use green threads instead of native threads because native threads have space overhead, not because they have time overhead. Attempting to spawn 100k OS threads will do strange things to most kernel scheduling algorithms; they're not optimized for that use-case.

Re: Zero-cost futures in Rust

#143

I'm rather surprised by the benchmark; I would expect the Go benchmark to be faster than Java (and the fact that it isn't may indicate some improvements that can be done to fasthttp by learning from rapidoid or minihttp). Then again, the difference isn't that much, so it just could be implementation details that would require a total refactor to fix.

Why would you expect that? AFAIK the Go compiler has a worse optimizer, a worse GC (at least throughput-wise) and possibly also a worse threading runtime. Since the benchmark measures steady-state performance and not memory or latency, and with the best Java server (probably optimized to almost never allocate) then Java having better code generation and threading could give it that much of an edge.

Actually, optimizer, GC and a threading runtime have almost nothing to do with Go's net/http performing that badly. The reasons are mostly in very poor design choices in the library itself that forced them to do a lot of implicit synchronization, unnecessary memory copying, unnecessary system calls, etc. It's just a huge mess, avoid it whenever possible.

Re: Zero-cost futures in Rust

#144
One thing I have not seen in discussion is - Work vs. Worker abstraction.

Your application work - computation logic/business rules, should be decoupled from the type of worker.

The worker can be - blocking or non-blocking - Futures/Continuations/Co-routines.

Re: Zero-cost futures in Rust

#145
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?

Re: Zero-cost futures in Rust

#146
post #45

Earlier quoted context omitted.

that sounds great but I guess that will make the compilation time bigger.

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?

Re: Zero-cost futures in Rust

#147
post #45

Earlier quoted context omitted.

that sounds great but I guess that will make the compilation time bigger.

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…

[deleted]

Re: Zero-cost futures in Rust

#148

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.

Re: Zero-cost futures in Rust

#149
post #142

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…

> On Linux, you don't actually gain that much if anything over 1:1 threading. You use green threads instead of native threads because native threads have space overhead, not because they have time overhead. Attempting to spawn 100k OS threads will do strange things to most kernel scheduling algorithms; they're not optimized for that use-case.

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

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.

[1]: https://github.com/rofl0r/musl/blob/d05aaedaabd4f5472c233dbb...

Re: Zero-cost futures in Rust

#150
post #122

Earlier quoted context omitted.

> So wondering if Rust provides any ability to add that kind of an N:M threading approach. Perhaps via an extension, macro or some other mechanism. I don't want M:N threading as Go implements it. It's a big loss of performance for marginal benefit over futures. In particular the libmill approach was tried in Rust and the results were far worse than 1:1. However, assuming this takes off I would like to see async/await…

> I don't want M:N threading as Go implements it. As someone who writes code for enterpricey businesses doing a lot of I/O bound stuff, golang style M:N threading is a godsend over Java's standard library, and other common platforms in that space. 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. With futures, the…

> In my problem space, M:N threading is simply worth it. And if I need anything better performing, I can still switch to C for specific use cases.

It maybe sounds like you should just use Go, which (as you point out) makes exactly those tradeoffs. I think Rust is aiming for a different market segment, with customers that want to make a different set of tradeoffs. Seems ideal to have both options. In particular, I don't think switching to C will ever be something Rust will want to require of its users.

Post reply on HN