I try to cancel Future, but still getting the execution code in .then().
Why is it not working and what am I doing wrong?
var c = CancelableOperation.fromFuture(
Future.delayed(new Duration(seconds: 5), () {
}).then((data){
print("123"); // This code is always called...
})
);
c.cancel();
https://pub.dartlang.org/packages/async
The CancelableOperation class defines an operation that can be canceled by its consumer. The producer can then listen for this cancellation and stop producing the future when it's received. It can be created using a CancelableCompleter.
Especially this part
The producer can then listen for this cancellation and stop producing
So the producer of the value is supposed to stop doing work. This doesn't mean it won't return a result. It might return null to indicate it is not an actual result.
What you want is probably the CancelableCompleter instead.
The unit tests might be helpful understanding how these classes are supposed to be used
https://github.com/dart-lang/async/blob/1106a5bfee1472905711da7a78dcd413ba2f6dcf/test/cancelable_operation_test.dart#L93-L134 (and also the others in this file)
Related
I just started learning asynchronous Rust, so this is propably not a difficult question to answer, however, I am scratching my head here.
I am not trying to run tasks in parallel yet, only trying to get them to run concurrently.
According to the guide at https://rust-lang.github.io/async-book/,
The futures::join macro makes it possible to wait for multiple different futures to complete while executing them all concurrently.
So when I create 2 Futures, I should be able to "await" both of them at once. It also states that
Whereas calling a blocking function in a synchronous method would block the whole thread, blocked Futures will yield control of the thread, allowing other Futures to run.
From what I understand here, if I await multiple Futures with join!, should the first one be blocked, the second one will start running.
So I made a very simple example where I created 2 async fns and tried to join! both, making sure the first one gets blocked. I used a mpsc::channel for the blocking, since the docs stated that thread::sleep() should not be used in async fns and that recv()
will always block the current thread if there is no data available
However, the behavior is not what I expected, as calling the blocking function will not yield control of the thread, allowing the other Future to run, like I would expect from the second quote I provided. Instead, it will just wait untill it is no longer blocked, finish the first Future and only then start the second. Pretty much as if they were synchronous and I would have just called one after the other.
My complete example code:
use std::{thread::{self}, sync::{mpsc::{self, Sender, Receiver}}, time::Duration};
use futures::{executor}; //added futures = "0.3" in cargo.toml dependencies
fn main(){
let fut = main_async();
executor::block_on(fut);
}
async fn main_async(){
let (sender, receiver) = mpsc::channel();
let thread_handle = std::thread::spawn(move || { //this thread is just here so the f1 function gets blocked by something and can later resume
wait_send_function(sender);
});
let f1 = f1(receiver);
let f2 = f2();
futures::join!(f1, f2);
thread_handle.join().unwrap();
}
fn wait_send_function(sender: Sender<i32>){
thread::sleep(Duration::from_millis(5000));
sender.send(1234).unwrap();
}
async fn f1(receiver: Receiver<i32>){
println!("starting f1");
let new_nmbr = receiver.recv().unwrap(); //I would expect f2 to start now, since this is blocking
println!("Received nmbr is: {}", new_nmbr);
}
async fn f2(){
println!("starting f2");
}
And the output is simply:
starting f1
Received nmbr is: 1234
starting f2
My question is what am I missing here, why does f2 only start after f1 is completed and what would I need to do to get the behavior I want (completing f2 first if f1 is blocked and then waiting for f1)?
Maybe the book is a little misleading, but when it refers to "a blocked future", it does not mean in the sense of blocking synchronous code (if that was the case, there would be no problem to use std::thread::sleep()), but rather, it means that the future is waiting to be polled by the executor.
Thus, std::mpsc that blocks the thread will not have the desired effect (definitely not on a single-threaded executor like future's, but it's a bad idea on multi-threaded executors too). Use futures::channel::mpsc and everything will work.
In the example on dart.dev the Future prints the message after the main function was done.
Why might the Future work after the main function was done? At first glance, after the completion of the main function, the entire work of the program is expected to be completed (and the Future must be cancelled).
The example code:
Future<void> fetchUserOrder() {
// Imagine that this function is fetching user info from another service or database.
return Future.delayed(Duration(seconds: 2), () => print('Large Latte'));
}
void main() {
fetchUserOrder();
print('Fetching user order...');
}
The program prints
Fetching user order...
Large Latte
I've expected just the following
Fetching user order...
This has to do with the nature of futures and asynchronous programming. Behind the scenes, Dart manages something called the asynchronous queue. When you initiate a future (either manually like you did with Future.delayed or implicitly by calling a method marked async, that function's execution goes into the queue whenever its execution gets deferred. Every cycle when Dart's main thread is idle, it checks the futures in the queue to see if any of them are no longer blocked, and if so, it resumes their execution.
A Dart program will not terminate while futures are in the queue. It will wait for all of them to either complete or error out.
The tutorial on async programming here talks about async await, but avoids discussing the Future API. I could find more information about the Future API here, but still I have some questions. These tutorials made me raise some questions, ideally I should have placed one for each questions, but since they are small and related I preferred to ask them all in one place.
What triggers/starts a Future execution?
From the text I can only conclude that once an async method returns the Future will be immediately triggered by the runtime.
What's the difference between Future.wait() and Future.then().then().then()?
Are return await myFuture; and return myFuture the same?
The text says an async method will return an incomplete Future once it sees an await or a return.
The text says:
Important: Async functions return Futures. If you don’t want your function to return a future, then use a different solution. For example, you might call an async function from your function.
How can we call an async function, get its return value, and not await, thus, not be an async function?
What triggers/starts a Future execution?
The code block for a Future is placed into the event queue, so it's executed when its turn in the event queue comes up. The Flutter in Focus Futures video has some good visuals about how this works.
What's the difference between Future.wait() and Future.then().then().then()?
They are different ways of handling multiple futures, but the differences are subtle. Future.wait handles errors slightly differently, and its values are returned as a list rather than in sequential code blocks, but in practice, the difference might not matter for your situation.
Are return await myFuture; and return myFuture the same?
No. In the first instance, execution is paused at the await until the Future is processed in the event queue. In the second instance, the Future itself is returned to the caller and execution continues as the caller wishes (probably until the Future is given a chance to be handled).
await is a language feature the essentially waits on the Future to complete at that point, whereas return simply returns the Future itself to the caller.
How can we call an async function, get its return value, and not await, thus, not be an async function?
If you need the return value, then you'd call the async function and then use it's Future directly rather than use await. Here's a silly example:
Future<int> getAsyncInt() async {
return 0;
}
void testAsync() {
getAsyncInt().then((value) {
print("Got an async int: $value");
});
}
In the above example, you can see we use an async function, but testAsync does not await the value (rather uses a Future, so the end result is the same).
If you don't need the return value though, you can just call the async function directly though:
Future<int> getAsyncInt() async {
return 0;
}
void testAsync() {
getAsyncInt();
}
In this second case, in fact, getAsyncInt() will indeed be called, even though it's return value is ignored by the caller.
These are good questions, BTW, hope that helps. async/await can be rather mysterious, but thinking of them as event queues really helps to understand in the flow of execution IMHO.
The ractive.set method returns a promise. When performing a simple set operation (single value or map) and then immediately referencing the new value via ractive.get, is it recommended to use the promise? Or is that completely unnecessary?
I've been avoiding the promise and found that I don't need it, but maybe I've just been lucky so far. Here's an example of what I mean:
ractive.set("foo", "bar");
console.log(ractive.get("foo")); // always outputs the correct value "bar"
I'm worried that the set operation is asynchronous and this will become evident on slower machines or if I start using the more advanced features of Ractive.
According to the Ractive docs:
[ractive.set] Returns a Promise that will be called after the set
operation and any transitions are complete.
Based on that, I wonder if the promise is really meant for post-transition work.
Based on that, I wonder if the promise is really meant for
post-transition work.
Exactly. The value update (and the resulting DOM changes per the template) happen synchronously, the promise is meant for asynchronous response to end of transitions.
This is also why the set operation also has a hash map option for the input parameters so multiple sets will be batched in one go:
ractive.set({
foo: 'foo',
bar: 'bar'
}).then( () => {
// this happens asynchronously ***after*** code execution has
// continued below on next event cycle or after transitions complete
});
// data and DOM have been updated as the code continues synchronously here:
console.log( ractive.get() );
I'm trying to learn how to use Meteor's wrapAsync helper. I want to use it to call an async function sequentially (not simultaneously). Though my code works, when it completes, the server restarts, which makes me wonder if there is a bug in my code. Unfortunately, there is no message saying why it restarted. Am I missing something?
The code is below and also on my MeteorPad demo.
var doAsyncIO = function (num, callback) {
setTimeout( function () {
// wrapAsync will use the following callback as the basis of returning results synchronously
callback(null, 'This is delayed result #' + num ); // nodeJS form: cb(error,result)
}, 2500); // wait 2.5 seconds before returning result
};
// Now create a synchronous version of doAsyncIO that sleeps, not blocks
// so that the CPU can do other tasks while waiting for the result
var doSyncIO = Meteor.wrapAsync(doAsyncIO);
// Now call doSyncIO twice sequentially (not simultaneously)
console.log('\n*** Starting first call to doSyncIO');
var result1 = doSyncIO(1);
console.log('result1:', result1);
// The following block runs after result1 is set (which is what I want)
console.log('\n*** Starting second call to doSyncIO');
var result2 = doSyncIO(2);
console.log('result2:', result2);
After a code change and after the console logs appear on the terminal, the terminal says the server restarts with no reason provided which makes me wonder if there is a bug in my code!
2015-04-19 Update: the restart message may not actually indicate a problem since it only shows up after a code change. Perhaps it's simply the standard restart message. Nevertheless, it seems like the restart message should really occur before the console logs.
Feel free to comment or fork my MeteorPad demo though to see if it's something else.