Hacker News new | past | comments | ask | show | jobs | submit login

People crap on async Rust because it's not the most graceful to use, but I think it's kinda genius how they've managed to make it zero-overhead. To the point that even the stack size of green "threads" is known ahead of time.

The only issue I have is that it's tough not to use it. The big HTTP libraries let you opt out, but smaller libraries don't have the resources to do everything twice. I don't know what the solution is, but it would be nice to always be able to chose. It's pretty silly to use async networking in a cli app, for example, but sometimes you have to.




> To the point that even the stack size of green "threads" is known ahead of time.

This is only possible by not having stacks for those "green threads" (they're stackless coroutines, not stackful fibers/proper green threads).

It puts a severe limitation on the usefulness and forces any kind of recursive coroutine to heap allocate on returns.


One other obvious alternative would have been to make all futures heap-allocate so that some can be recursive.

I think making recursive futures invoke `Box` or similar seems consistent with Rust's general "only pay for what you actually use".


I disagree, because you're paying for boxing on return + dynamic dispatch when it's perfectly safe/sound to have a stackful coroutine that only allocates when the stack needs to grow and doesn't require dynamic dispatch. So you don't pay for heap allocated futures if they aren't necessary, and you pay less when they are.

So you're actually paying a higher price than if the compiler could support stackful generators for recursive futures. In fact async just gets a lot easier to write and use if generators could be stackful, at least imho. Generators don't have the syntax nice-ness of async/await, but they're also more explicit which feels more in with the rest of Rust, where syntax sugar like async/.await() is the exception and not the norm.


Fair enough, if we could create generators and futures that switch stacks that might work.


stackful coroutines break FFI


How so? You can swap stacks in posix just fine modulo some setjmp/longjmp shenanigans. But exceptions aren't sound across FFI either.


> The big HTTP libraries let you opt out (of async)

At least for reqwest it just wraps the async code in something like `block_on`: https://github.com/seanmonstar/reqwest/blob/5397d2cf8eaecc9f...

And as the sibling comment says, you can do that in your own code. It does still add Tokio to your binary size, and add some compile time, and probably start a bunch of worker threads you don't need, but it does work.


You can always just do let no_async = block_on(something_async);


I'd instinctively worry about overhead there

Are there benchmarks comparing sync http libraries with block_on-wrapped async http libraries?


> I'd instinctively worry about overhead there

Yeah, one of the nice things about blocking I/O is that you can perform it with a single syscall. With block_on(async_io), you're now dealing with registration with a reactor, polling epoll, and extra syscalls for each I/O operation. Not to mention the overhead of running the state-machine as opposed to line by line.


Is the overhead going to matter if your content to block anyway? Surely any threading etc constructs are tiny compared to wire time, etc.


Blocking I/O+threads can actually scale very well now, and with block_on you get the worst of both worlds, but yeah, I agree that most people are probably fine with it.


Most people fine with python. Those who come to Rust are not fine with overhead.


This assumes that people only use Rust for the performance. I don't think that's strictly true.

95% of what I write isn't performance-critical or even, really, performance-relevant. I still choose Rust for the vast majority of projects for ergonomic and correctness reasons.


You're spot on. I recently chose Rust over Python for a very small program which reads a JSON (or Hjson) file, does some checking and processing, and writes the results to a different JSON file, because Rust has serde, proper static type checking, algebraic data types, and other features that made it more productive than Python (!!!) for that specific use case. Performance wasn't even a consideration, I made judicious use of clone() and run it in debug mode.


Serde is such an awesome library. Having to decode serialized data in the other languages (Swift, C++, Python) I write is such a bear after using serde.

Swift comes closest with codable/decodable but it's often still lacking the ergonomics of serde, especially the attribute options per field


Some people who come to rest may not be fine with it.

A lot of people come to rust for other reasons, like compile time safety checks etc...

But most importantly, the delta between the performance of block_on and not, versus block_on and Python are massively different. You can write inefficient rust and still have a huge win over Python.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: