Live data from Hacker News

How to think about async/await in Rust

cliffle.com

21–30 of 268 posts

Re: How to think about async/await in Rust

#21

Not specific to rust, but I think asynchronous programming in general is a hype. It didn't start because it is so awesome, it started because JS can't do parallel any other way. That's the long and short of it. People wanted to use JS in the backend for some reason. The backend requires concurrency. JS cannot do concurrency. Enter the event loop. Then enter some syntactic sugar for the event loop. And since JS is pop…

For me async/await was a godsend. I've had so bad experiences with multithreading in C++, where I ended up in a Semaphore/Mutex hell in a big project, that async/await is a really welcome compromise between using idle CPU resources and just not doing multiple things at once.

Then there's `#[tokio::main(flavor = "multi_thread", worker_threads = 2)]` which actually lets you use multithreading with async/await which is just a nice feature to have, given that Python can't do this due to the GIL. But asyncio in Python is also so great.

Re: How to think about async/await in Rust

#22
post #15

I think Go got it right by inverting the logic around async/await. In Go you have to explicitly state that a function is to run in the background via "go fn(...)". This makes it much clearer that this code will execute concurrently. In the async/await world you can't tell by looking at a function call if it will block until it's done. Forgot an await? No compile error but your program might behave in weird ways. This…

> Haven't done too much async Rust yet but I don't think it solved this issue from what I've seen.

If you don't await your variable contains a future - how are you using that like e.g. an int, without a compiler error?

Re: How to think about async/await in Rust

#23

Not specific to rust, but I think asynchronous programming in general is a hype. It didn't start because it is so awesome, it started because JS can't do parallel any other way. That's the long and short of it. People wanted to use JS in the backend for some reason. The backend requires concurrency. JS cannot do concurrency. Enter the event loop. Then enter some syntactic sugar for the event loop. And since JS is pop…

It began in C# in 2012 - 5 years before JavaScript. And C# does threads. And made its way to JavaScript via Typescript (whose creator also created C#).

Re: How to think about async/await in Rust

#24
post #15

I think Go got it right by inverting the logic around async/await. In Go you have to explicitly state that a function is to run in the background via "go fn(...)". This makes it much clearer that this code will execute concurrently. In the async/await world you can't tell by looking at a function call if it will block until it's done. Forgot an await? No compile error but your program might behave in weird ways. This…

It's actually very likely you'll have a compile error. Async functions return a Future (like a Promise in JS) and this isn't a value you can typically use inplace of others. There are also an on-by-default warning if you don't use the Future value at all

Re: How to think about async/await in Rust

#25
post #15

I think Go got it right by inverting the logic around async/await. In Go you have to explicitly state that a function is to run in the background via "go fn(...)". This makes it much clearer that this code will execute concurrently. In the async/await world you can't tell by looking at a function call if it will block until it's done. Forgot an await? No compile error but your program might behave in weird ways. This…

It wouldn't work. In Go, it doesn't matter how deeply nested a call to a blocking function is, when you do "go f()" the runtime takes care of things.

With async however, if "await" is the default, then as soon as an async function calls another async function, it would block, completely defeating the point of async in the first place.

I guess you could flip the rules and say that within an async function async is the default and within a regular function await is the default, but actually in most languages a regular function can't call an async function directly because async needs to propagate all the way to the event loop. So you'd just have async as the default again.

My explanation sucks but if you want to go into this rabbit hole look up "stackful vs stackless coroutines".

Re: How to think about async/await in Rust

#26
post #22
post #15

I think Go got it right by inverting the logic around async/await. In Go you have to explicitly state that a function is to run in the background via "go fn(...)". This makes it much clearer that this code will execute concurrently. In the async/await world you can't tell by looking at a function call if it will block until it's done. Forgot an await? No compile error but your program might behave in weird ways. This…

> Haven't done too much async Rust yet but I don't think it solved this issue from what I've seen. If you don't await your variable contains a future - how are you using that like e.g. an int, without a compiler error?

The issue arises if you don't use the returned value. Lets say there's a function "async fn saveToDisk()". You call this function before you exit the program. Now if you forget to use await on it, your program will exit without having saved the data to disk.

Re: How to think about async/await in Rust

#27
post #15

I think Go got it right by inverting the logic around async/await. In Go you have to explicitly state that a function is to run in the background via "go fn(...)". This makes it much clearer that this code will execute concurrently. In the async/await world you can't tell by looking at a function call if it will block until it's done. Forgot an await? No compile error but your program might behave in weird ways. This…

You're talking about particular JS implementation problems, not general async/await problems.

> In Go you have to explicitly state that a function is to run in the background via "go fn(...)".

In Rust you have to explicitly `spawn` a task to detach it from the current coroutine and make it run in background. Typically this is much more costly than not spawning and executing async function concurrently as part of the same coroutine's state machine (and Go actually doesn't give you that option at all).

> In the async/await world you can't tell by looking at a function call if it will block until its done.

   foo().await();  
> Forgot an await? No compile error

   warning: unused implementer of `futures::Future` that must be used
> Why can't "await" be the default when calling an async function

For similar reasons you don't want `clone()` to be implicit or rethrowing errors to be implicit (like exceptions in Java).

Awaiting implicitly would hide a potentially long and important operation. Await typically means the control is yielded back to the executor and it can switch to another task. You don't want it in a language that wants to give as much control about performance as possible to the developer. Being able to see that "this fragment of code will never be preempted" is a great thing for predictability. Rust is not Go/Java - nobody is going to celebrate achieving sub 1 ms latency here.

Additionally there are certain things you are not allowed to keep across await points, e.g. mutex guards or other stuff that's not safe to switch between threads. E.g. using a thread-local data structure across await points might break, because you could be on a different thread after await. If await was hidden, you'd likely be much more surprised when the compiler would reject some code due to "invisible" await.

Re: How to think about async/await in Rust

#29

Not specific to rust, but I think asynchronous programming in general is a hype. It didn't start because it is so awesome, it started because JS can't do parallel any other way. That's the long and short of it. People wanted to use JS in the backend for some reason. The backend requires concurrency. JS cannot do concurrency. Enter the event loop. Then enter some syntactic sugar for the event loop. And since JS is pop…

In C, I have written and worked on a lot of code that is event-based. Async is a natural extension to that.

So, no it is not a hype. These types of techniques have been used for a very long time.

Re: How to think about async/await in Rust

#30
post #3

Not specific to rust, but I think asynchronous programming in general is a hype. It didn't start because it is so awesome, it started because JS can't do parallel any other way. That's the long and short of it. People wanted to use JS in the backend for some reason. The backend requires concurrency. JS cannot do concurrency. Enter the event loop. Then enter some syntactic sugar for the event loop. And since JS is pop…

Your comment seems to be conflating concurrency with parallelism. JS doesn't have any language-level abstractions for parallelism (async or not) but you do have Web Workers[0] and process forking (depending on runtime) to get actual parallel programming. JS async deals with concurrency, not parallelism. Threads are the opposite: They are interfaces for parallel programming and their use is orthogonal to how your appl…

[deleted]
Post reply on HN