Live data from Hacker News

Rust without the async (hard) part

lunatic.solutions

21–30 of 136 posts

Re: Rust without the async (hard) part

#21
Does anyone else get the feeling that we (as a field) are missing something basic about concurrency? Like there's a really elegant solution just around the corner, that has the low overhead of async/await without the complexity. Or otherwise put, the ease of goroutines but without GC.

I know it sounds crazy. I recently dove into the area, and was pretty surprised at how many interesting building blocks there are out there. It feels like if we just combine them in the right way, we'll discover something that works a lot better.

Off the top of my head:

Google discovered a way to switch between OS threads without the syscall overhead. All it needs is to solve the memory overhead. [0]

Zig discovered a way to use monomorphization to enable colorless async/await. If someone could figure out how to make it work through polymorphism / virtual dispatch, that would be amazing. [1]

Vale discovered a possible way to make structured concurrency in a memory safe way that's easier than existing methods. [2]

Go [3] and Loom [4] show us that we can move stacks around. Loom is particularly interesting as it shows we can move the stack to its original location, a unique mechanism that could solve some other approaches' problems with pointer invalidation.

Cone is designing a unique blend of actors and async await, to enable simpler architectures. [5]

We're close to solving the problem, I can feel it.

[0] No public docs on it, but TL;DR: we tell the OS the thread is blocked, and manually switch over to it by saving/manipulating registers.

[1] https://kristoff.it/blog/zig-colorblind-async-await/

[2] https://verdagon.dev/blog/seamless-fearless-structured-concu...

[3] https://blog.cloudflare.com/how-stacks-are-handled-in-go/

[4] https://youtu.be/NV46KFV1m-4

[5] Can't find the link, but was a discussion on their server.

Re: Rust without the async (hard) part

#22
post #15
post #3

Anything using the green/lightweight or OS thread model is usually easier to use at the cost of some runtime performance. Whether the runtime performance matters for your use case can only be determined by measuring stuff. The perception that async rust is where you should start for concurrent rust because it's built in and everyone uses it perhaps should be revisited. I would argue that the other options are worth c…

Too many major packages in the ecosystem only support an async model now. It's pretty frustrating if you are just writing a synchronous program, or one with a straightforward OS threading model.

There's a neat crate for that I recently found: https://crates.io/crates/pollster

Re: Rust without the async (hard) part

#23
post #15
post #3

Anything using the green/lightweight or OS thread model is usually easier to use at the cost of some runtime performance. Whether the runtime performance matters for your use case can only be determined by measuring stuff. The perception that async rust is where you should start for concurrent rust because it's built in and everyone uses it perhaps should be revisited. I would argue that the other options are worth c…

Too many major packages in the ecosystem only support an async model now. It's pretty frustrating if you are just writing a synchronous program, or one with a straightforward OS threading model.

This "async virality" syndrome is the main reason why async is harmful imho. _Some_ async can be very useful in certain constrained circumstances, I believe. However forcing the async execution model on all code is a terrible idea.

Re: Rust without the async (hard) part

#24
post #15
post #3

Anything using the green/lightweight or OS thread model is usually easier to use at the cost of some runtime performance. Whether the runtime performance matters for your use case can only be determined by measuring stuff. The perception that async rust is where you should start for concurrent rust because it's built in and everyone uses it perhaps should be revisited. I would argue that the other options are worth c…

Too many major packages in the ecosystem only support an async model now. It's pretty frustrating if you are just writing a synchronous program, or one with a straightforward OS threading model.

If your program is mostly synchronous, you can manually create the async runtime and just use block_on to call async functions from a sync context: https://tokio.rs/tokio/topics/bridging#a-synchronous-interfa...

Re: Rust without the async (hard) part

#25
post #15

Earlier quoted context omitted.

Too many major packages in the ecosystem only support an async model now. It's pretty frustrating if you are just writing a synchronous program, or one with a straightforward OS threading model.

This "async virality" syndrome is the main reason why async is harmful imho. _Some_ async can be very useful in certain constrained circumstances, I believe. However forcing the async execution model on all code is a terrible idea.

How would you propose mixing async and sync code from an implementation perspective?

Re: Rust without the async (hard) part

#26

Does anyone else get the feeling that we (as a field) are missing something basic about concurrency? Like there's a really elegant solution just around the corner, that has the low overhead of async/await without the complexity. Or otherwise put, the ease of goroutines but without GC. I know it sounds crazy. I recently dove into the area, and was pretty surprised at how many interesting building blocks there are out…

I just want to say there are mountains of research on this, and recent development is exciting, but some of the techniques (like stack switching and moving) are very old. Project Loom is very intriguing because of how it solves the practical problems of introducing old concurrency techniques into existing language implementations that were not designed around them.

A lot of this stuff is intriguing from the implementation side, but where we're really lacking is in the syntax and semantic side to make concurrency "make sense" to programmers. I don't think we're close to solving that problem (for example, call/cc isn't the answer, it's the problem).

imho the issue isn't function coloring, threads, whatever. It's a compiler that defaults to async code in the calling convention and then optimization passes to de-async-ify (remove unnecessary yield points) the code at compile time. The result would be code that looks synchronous but is async where it matters (i/o).

A lot of the symptoms of the sync/async problem are caused by the explicit decoupling of sync/async APIs in source code. If you remove that and force it to be implicit internal to the language implementation, the issue goes away. It would take a lot of work to determine if that was worth it.

Basically as we've now accepted garbage collection to be an acceptable part of language implementation, one day I think we'll accept async executors to be a part of that too. We're halfway there on the impl side (Go, Java through Loom, NodeJS, etc). The other half is removing the explicit syntax for it.

Re: Rust without the async (hard) part

#27
post #22
post #15

Earlier quoted context omitted.

Too many major packages in the ecosystem only support an async model now. It's pretty frustrating if you are just writing a synchronous program, or one with a straightforward OS threading model.

There's a neat crate for that I recently found: https://crates.io/crates/pollster

Thanks, that looks great.

Re: Rust without the async (hard) part

#28
post #15

Earlier quoted context omitted.

Too many major packages in the ecosystem only support an async model now. It's pretty frustrating if you are just writing a synchronous program, or one with a straightforward OS threading model.

If your program is mostly synchronous, you can manually create the async runtime and just use block_on to call async functions from a sync context: https://tokio.rs/tokio/topics/bridging#a-synchronous-interfa...

Even simpler to use `futures::executor::block_on`. No need to create a runtime, you can just call the function.

https://docs.rs/futures/latest/futures/executor/fn.block_on....

Re: Rust without the async (hard) part

#29

I use Rust for the amazing types, map/filter/reduce, and, even if I never write macros myself, beautiful libraries like serde and clap. I do need to often use async to wait for multiple network requests at once, although I'm not quite comfortable with it. Requesting urls n-at-a-time took me a while ( https://play.rust-lang.org/?version=stable&mode=debug&editio... ). In particular rust-analyzer itself cannot figure ou…

Sometime ago I was comparing go, python and Rust to do some GET request asynchronous.

At first, I noticed that the go version was actually faster than the Rust one, and then I saw that in `reqwest`, they recommend you if you're doing multiple GET request, to create a `Client` and then use that to get better performance[1]. After changing my code, the Rust version was effectively a bit faster (not by much, to be honest, which was a bit disappointing considering go's version was way easier to write, and I say this as a generally rust shill).

Hopefully this comment is somewhat helpful :)

[1] https://docs.rs/reqwest/latest/reqwest/#making-a-get-request

Re: Rust without the async (hard) part

#30
post #15

Earlier quoted context omitted.

Too many major packages in the ecosystem only support an async model now. It's pretty frustrating if you are just writing a synchronous program, or one with a straightforward OS threading model.

This "async virality" syndrome is the main reason why async is harmful imho. _Some_ async can be very useful in certain constrained circumstances, I believe. However forcing the async execution model on all code is a terrible idea.

A great example of this would be in javascript testing frameworks. There must be dozens of frontend test frameworks that shoehorn inherently synchronous, procedural tasks into awkward syntax of sugared promise chains.
Post reply on HN