I have an async computation like the following (see inline comments):
async {
//...
do! Async.Sleep(100) //cancellation may happen during sleep
//... but isn't checked at the end of the sleep, so regular, non-async computations are executed here
}
In order to force a cancellation check / terminate the entire async computation before the "regular" computation part is reached, I insert an effective no-op do! Async.Sleep(1) immediately after the do! Async.Sleep(100). Is there a cleaner way to do this? Possibly even something like do! Async.Nop.
How about something like this:
let nop = async.Return ()
Then you could use it like:
async {
// ...
do! Async.Sleep 100
do! nop
}
Related
I'm trying to execute several sqlx queries in parallel given by a iterator.
This is probably the closest I've got so far.
let mut futures = HahshMap::new() // placeholder, filled HashMap in reality
.iter()
.map(async move |(_, item)| -> Result<(), sqlx::Error> {
let result = sqlx::query_file_as!(
// omitted
)
.fetch_one(&pool)
.await?;
channel.send(Enum::Event(result)).ignore();
Ok(())
})
.clollect();
futures::future::join_all(futures);
All queries and sends are independent from each other, so if one of them fails, the others should still get processed.
Futthermore the current async closure is not possible like this.
Rust doesn't yet have async closures. You instead need to have the closure return an async block:
move |(_, item)| async move { ... }
Additionally, make sure you .await the future returned by join_all in order to ensure the individual tasks are actually polled.
I'm trying to use async-std's task::spawn:
use std::time::Duration;
async fn w() {
loop {
task::sleep(Duration::from_secs(1)).await;
println!("Tick");
}
}
#[async_std::main]
async fn main() {
println!("Start");
task::spawn(w()).await;
println!("End");
}
I expect that "End" is immediately printed after "Start", but the "Tick" loop is printed endlessly.
So what is exactly the difference to the following?
#[async_std::main]
async fn main() {
println!("Start");
w().await;
println!("End");
}
Don't .await the spawned task. Doing so is like joining a thread: it waits for the task to finish before continuing. The handle spawn returns does not need to be awaited in order for the task to be driven to completion.
task::spawn(w()).await;
As written, you are correct that task::spawn(w()).await is no different than w().await. They both block the thread waiting for w() to finish.
What's the purpose of awaiting a spawn call, then? It's useful if you want to spawn a background task, do some other work on the current thread, and then block.
let handle = task::spawn(w());
do_other_things_for_a_while();
// Block and retrieve the result.
let result = handle.await;
In JavaScript, async code is written with Promises and async/await syntax similar to that of Rust. It is generally considered redundant (and therefore discouraged) to return and await a Promise when it can simply be returned (i.e., when an async function is executed as the last thing in another function):
async function myFn() { /* ... */ }
async function myFn2() {
// do setup work
return await myFn()
// ^ this is not necessary when we can just return the Promise
}
I am wondering whether a similar pattern applies in Rust. Should I prefer this:
pub async fn my_function(
&mut self,
) -> Result<()> {
// do synchronous setup work
self.exec_command(
/* ... */
)
.await
}
Or this:
pub fn my_function(
&mut self,
) -> impl Future<Output = Result<()>> {
// do synchronous setup work
self.exec_command(
/* ... */
)
}
The former feels more ergonomic to me, but I suspect that the latter might be more performant. Is this the case?
One semantic difference between the two variants is that in the first variant the synchronous setup code will run only when the returned future is awaited, while in the second variant it will run as soon as the function is called:
let fut = x.my_function();
// in the second variant, the synchronous setup has finished by now
...
let val = fut.await; // in the first variant, it runs here
For the difference to be noticeable, the synchronous setup code must have side effects, and there needs to be a delay between calling the async function and awaiting the future it returns.
Unless you have specific reason to execute the preamble immediately, go with the async function, i.e. the first variant. It makes the function slightly more predictable, and makes it easier to add more awaits later as the function is refactored.
There is no real difference between the two since async just resolves down to impl Future<Output=Result<T, E>>. I don't believe there is any meaningful performance difference between the two, at least in my empirical usage of both.
If you are asking for preference in style then in my opinion the first one is preferred as the types are clearer to me and I agree it is more ergonomic.
I'm facing a problem with async methods and Future in Dart.
I think I did/understood something wrong but I don't know what.
I'm trying to figure out the difference between Future and async and understand how the event loop works. I read the documentation and a lot of articles about that. I thought I understood so I tried to write some code that create a Future object with a sleep() call in it.
First, I tried with Future and I think it's behaving like it should:
main(List<String> arguments) {
print('before future');
test_future();
print('after future');
}
test_future() {
Future (() {
print('Future active before 5 seconds call');
sleep(Duration(seconds: 5));
print('Future active after 5 seconds call');
}).then((_) => print("Future completed"));
}
So this returns:
print before future
create a future object, put it in the event queue and return immediately
print after future
call the code of the future from the event queue
print before 5 seconds
wait 5 seconds
print after 5 seconds*
print future completed
I think all of this is normal.
Now, i'm trying to do the same with async. From the documentation, adding the async keyword to a function make it return a Future immediately.
So I wrote this:
main(List<String> arguments) {
print('before future 2');
test().then((_) => print("Future completed 2"));
print('after future 2');
}
test() async {
print('Future active before 5 seconds call');
sleep(Duration(seconds: 5));
print('Future active after 5 seconds call');
}
Normally, when calling test().then(), it should put the content of test() in the event queue and return a Future immediately but no. The behavior is this one:
print before future 2
call test() function (should return a future I think, but the code is executed right now)
print before 5 seconds
wait for 5 seconds
print after 5 seconds
print future completed 2
print after future 2
Can someone explain if I did not use async properly or if there is something wrong ?
Best
You should be aware that sleep() just blocks the whole program. sleep() is not related in any way to the event loop or async execution. Perhaps you want to use instead:
await Future.delayed(const Duration(seconds: 5), (){});
async system calls do not block the isolate. The event queue is still processed, (continues immediately after invoking the system call). If you make sync system calls, they block like sleep.
There are often sync and async variants in dart:io of system calls like api.dartlang.org/stable/2.2.0/dart-io/File/readAsLinesSync.html. Even though sleep does not have the sync suffix, it's sync and no way to work around. You can use Future.delayed() as shown above to get the effect in an async way.
I have a blocking call blockingFoo() that I would like to use in an async context. I would like to run it on another thread, so as to not block the async.
Here is my solution:
let asyncFoo =
async {
blockingFoo() |> ignore
}
|> Async.StartAsTask
|> Async.AwaitTask
Is this the correct way to do this?
Will this work as expected?
I think you're a bit lost. Async.StartAsTask followed by Async.AwaitTask effectively cancel each other, with the side-effect that the Task created in the process actually triggers evaluation of the async block containing blockingFoo on the thread pool. So it works, but in a way that betrays expectations.
If you want to trigger evaluation of asyncFoo from within another async block, a more natural way to do it would be to use Async.Start if you don't want to await its completion, or Async.StartChild if you do.
let asyncFoo =
async {
blockingFoo() |> ignore
}
async {
// "fire and forget"
asyncFoo |> Async.Start
// trigger the computation
let! comp = Async.StartChild asyncFoo
// do other work here while comp is executing
// await the results of comp
do! comp
}