I'm not trying to get any result value from it, but just benefit from the async syntax.
async fn hi(){
some.await?
task.await?
// catch some error if needed, but don't return anything
}
hi() // run this without await
hi() // run this without await
hi() // run this without await
hi() // run this without await
Async functions must be run inside some runtime. The probably easiest way to go is to add the dependency on tokio and then annotate main function with #[tokio::main] - this way runtime will be created for you by the attribute, and main can be treated as async itself, including having awaits inside.
Yes, that is exactly the idea. In Rust, Futures are lazy. They need to be explicitly awaited to make them run (to completion) or polled to make them run (perhaps not to completion).
A Future has a method poll, which quite literally does what it's name suggests. However, directly calling poll requires you to jump through some hoops, because of the types of the parameters of poll (notice, the Pin on the self and the Context argument). The async book has a chapter showing how to do it.
Sometimes you want to cancel futures once one future has completed. For that, you could use futures::select! or tokio::select!.
When you want enable truly parallel execution (i.e. on different CPUs), you will need to use a spawn function of the runtime you're using, e.g. tokio::spawn. You can then (edit: if/when you want to retrieve the result) pass the resulting future to await, join!, or select!, whichever suits you best.
Spawn is almost certainly what you want here. It isn't guaranteed to run on another thread, but it's likely to. Join or select are for when you need to process the results, but you can use the JoinHandle returned from spawn for that too, with a small inefficiency.
Futures in Rust work a lot different than promises in JavaScript. There are similarities, but they are still very different.
In Rust you must await a future if you want it to do anything, or you must give it to some other funciton that will poll the future.
Polling futures manually is not like calling .then() on a promise in JavaScript, it is a much more complicated process that is done by the async executor, and is like what the JavaScript engine does for you with JavaScript promises.
If you simply want to get a value out of a Rust future, you pretty much use .await or a combiner like join, or a spawner like spawn.
I think polling is what I'm looking for, but It's hard to know how to start.
There are just some functions that have some async syntax inside, but I don't really need to await them.
Rather just some error hadling inside that async, but the caller doesn't really have to worry about the result.
Ah, OK, I think I get it. In that case you can let async_std do the polling for you:
use async_std::task::block_on;
async fn hi(){
some.await?
task.await?
// catch some error if needed, but don't return anything
}
block_on(hi()) // run this without await
block_on(hi()) // run this without await
block_on(hi()) // run this without await
block_on(hi()) // run this without await
That will do the polling for you, while blocking the current thread until it is done, every time you call block_on().
If you want to run multiple futures concurrently, without blocking on them, that is what your async runtime's spawn() function is for. Something has to poll the futures to cause them to make progress, and spawn() is telling the runtime to do that for you without further interaction.
Instead of this, you can put the join handles in a collection, and then await them. That way, all the spawning happens before you wait, and you can wait whenever you want.
let handles: Vec<_> = (1..=7).map(|i| task::spawn(init(i))).collect();
// do anything else you want between these — the tasks will be running
// Wait for all the tasks to finish
for handle in handles {
handle.await;
}
Or, you can run them concurrently without actually spawning, with join_all:
use futures::future::join_all;
join_all((1..=7).map(|i| task::spawn(init(i)))).await;
This waits until they all finish, but lets them all run simultaneously rather than in sequence. This is appropriate for getting the work done quickly but waiting for it; spawn is appropriate for when you don't care when it finishes and the program will continue running.
There are lots of options here, but the right one depends on exactly what you want to happen.
(The reason your spawns didn't finish without any awaits is analogous to how in JS, all your code stops running if the user closes the web page; everything stops when main() returns in a Rust program.)