I am attempting to put in a pause between a forEach loop for a list.
I would have thought the timeout would cause a pause for the loop but it just seems to start 3 timers all at once. (In very quick succession.)
startTimeout(int seconds) async {
print('Timer Being called now');
var duration = Duration(seconds: seconds);
Timer(duration, doSomething());
}
startDelayedWordPrint() {
List<String> testList = ['sfs','sdfsdf', 'sfdsf'];
testList.forEach((value) async {
await startTimeout(30000);
print('Writing another word $value');
});
}
Any idea how I might do this?
Use await Future.delayed() to pause for certain duration and a simple old for(...in...){} loop, instead of forEach() to iterate the values.
If forEach() receives async functions, each iteration call will run in a separate asynchronous context which can be reasoned about similarly to parallel code execution. Meanwhile forEach it self will return immediately without waiting until any async function to complete.
How to Async/await in List.forEach() in Dart
Sample:
https://dartpad.dartlang.org/a57a500d4593aebe1bad0ed79376016c
main() async {
List<String> testList = ['sfs','sdfsdf', 'sfdsf'];
for(final value in testList) {
await Future.delayed(Duration(seconds: 1));
print('Writing another word $value');
};
}
Related
In Node.js I can set the interval that a certain event should be triggered,
function intervalFunc() {
console.log('whelp, triggered again!');
}
setInterval(intervalFunc, 1500);
However the interface for Tokio's interval is a bit more complex. It seems to be a something to do with a much more literal definition of an interval, and rather than calling a function at an interval, it simply stalls the thread until the time passes (with .await).
Is there a primitive in Tokio that calls a function "every x seconds" or the like? If not, is there an idiom that has emerged to do this?
I only need to run one function on a recurring interval... I don't care about other threads either. It's just one function on Tokio's event loop.
Spawn a Tokio task to do something forever:
use std::time::Duration;
use tokio::{task, time}; // 1.3.0
#[tokio::main]
async fn main() {
let forever = task::spawn(async {
let mut interval = time::interval(Duration::from_millis(10));
loop {
interval.tick().await;
do_something().await;
}
});
forever.await;
}
You can also use tokio::time::interval to create a value that you can tick repeatedly. Perform the tick and call your function inside of the body of stream::unfold to create a stream:
use futures::{stream, StreamExt}; // 0.3.13
use std::time::{Duration, Instant};
use tokio::time; // 1.3.0
#[tokio::main]
async fn main() {
let interval = time::interval(Duration::from_millis(10));
let forever = stream::unfold(interval, |mut interval| async {
interval.tick().await;
do_something().await;
Some(((), interval))
});
let now = Instant::now();
forever.for_each(|_| async {}).await;
}
async fn do_something() {
eprintln!("do_something");
}
See also:
How can I run a set of functions concurrently on a recurring interval without running the same function at the same time using Tokio?
I am still a rust/tokio beginner, but I did find this solution helpful for myself:
use std::time::Duration;
use tokio::time;
use tokio_stream::wrappers::IntervalStream;
#[tokio::main]
async fn main() {
let mut stream = IntervalStream::new(time::interval(Duration::from_secs(1)));
while let Some(_ts) = stream.next().await {
println!("whelp, triggered again!");
}
}
Please note that _ts holds the execution timestamp.
I am trying to make a while loop loop a statement exactly for one second after which it stops. I have tried this in DartPad, but it crashes the browser window.
void main(){
var count = 0.0;
bool flag = true;
Future.delayed(Duration(seconds: 1), (){
flag = false;
});
while (flag){
count++;
}
print(count);
}
Am I doing something wrong?
I like how you are trying to figure Futures out. I was exactly where you were before I understood this stuff. It's kind of like threads, but quite different in some ways.
The Dart code that you wrote is single threaded. By writing Future.delayed, you did not start a job. Its execution won't happen unless you let go of the thread by returning from this main function.
Main does not have to return if it is marked with async.
Two actions have to run "concurrently" to be able to interact with each other like you are trying to do. The way to do it is to call Future.wait to get a future that depends on the two futures. Edit: Both of these actions have to let go of execution at every step so that the other can get control of the single thread. So, if you have a loop, you have to have some kind of await call in it to yield execution to other actions.
Here's a modified version of your code that counts up to about 215 for me:
Future main() async {
var count = 0.0;
bool flag = true;
var futureThatStopsIt = Future.delayed(Duration(seconds: 1), (){
flag = false;
});
var futureWithTheLoop = () async {
while (flag){
count++;
print("going on: $count");
await Future.delayed(Duration(seconds: 0));
}
}();
await Future.wait([futureThatStopsIt, futureWithTheLoop]);
print(count);
}
Consider the following code:
Loop::run(function() {
Loop::onSignal(SIGINT, function () use ($w) {
echo "Caught SIGINT! exiting ...\n";
Loop::stop();
});
while([$jobId, $jobData] = yield $beanstalk->reserve()) {
$response = yield $httpClient->send($request);
yield $beanstalk->delete($jobId);
}
});
To my understanding, when this code receives a SIGINT, the callback in Loop::onSignal will be executed on the next tick and thus the loop will stop and the program exit.
In this case, if $httpClient->send() in the while loop has not yet finished, the next line will not be executed and the Beanstalk message will not get deleted. The Beanstalk job will then be retried and that might cause a problem if the HTTP request is not idempotent. We can substitute an HTTP request with a database call.
Is there a way to tell the loop to not execute new generators and wait for the generators in-progress to finish when a SIGINT is received?
I've been trying to wrap my head around this but couldn't find a solution.
There's no such option, but you can achieve what you want in your simple application pretty easily by adding a flag.
Loop::run(function() {
$running = true;
Loop::onSignal(SIGINT, function () use (&$running) {
echo "Caught SIGINT! exiting ...\n";
$running = false;
});
while($running && [$jobId, $jobData] = yield $beanstalk->reserve()) {
$response = yield $httpClient->send($request);
yield $beanstalk->delete($jobId);
}
});
This will simply continue with the current request and exit afterwards.
How can I achieve a loop like this:
foobar.each(function (model, j) {
// asynchrounous call etc. {in here bool get set to true}
// outside all asynchronous calls
// wait till bool is true, without stopping anything else except the loop to the top of
the _.each
})
I asked a similar question yesterday. But it got marked as a duplicate when it wasn't the same case. Their solution did not achieve the same thing. Also generator functions were suggested which looked like it would work. But I can't use them with ecmascript 5
I've tried busy loops and set time out but they don't seem to work either
I've also tried this:
goto();
function goto() {
if (foo === true) {
//return true; /*I've tried with and without the return because the loops
doesn't need a return*/
} else {
goto();
}
}
What happens with the goto() method is it breaks. Giving me the right results for the first iterations then execution seems to stop altogether. 'foo' always gets set to true in normal execution though.
What you could do is implement a foreach yourself, where you execute your condition, and then on success callback go to the next item (but meanwhile the rest of the code will keep running.
var iteration = 0 //count the iteration of your asynchronous process
//start looping
loop(iteration)
function loop(iteration){
var model = foobar[iteration];
//exit your loop when all iterations have finished (assuming all foobar items are not undefined)
if (foobar[iteration] === undefined){
return;
}
//do what you want
//on success callback
iteration++;
loop(iteration);
//end success callback
}
I am facing a weird case, I am using google directionsService.route. but it doesn’t sync well. Here is my code:
angular.forEach(requestArray, function(v, i) {
directionsService.route(v, function(result, status) {
var googleLeg = result.routes[0].legs[0];
// sth else...
});
});
As you can see, I am looping the location Array into the route. every time I fire the function, it will go through the requestArray first, (if we make a breakpoint on the line (var googleLeg = result.routes[0].legs[0]), it doesn’t reach there until it goes through all the requestArray.(i from 0 - length); then it will have the second loop for directionsService.route( at this time, it will reach to line(var googleLeg = result.routes[0].legs[0]); Any idea about this?
Essentially your problem is that calling a google service is an asynchronous call, and you are not guaranteed when the callback will execute. If you need to process requestArray synchronously, here is what you can do:
function start() {
// create a copy of request array
var stuff = [].slice.call(requestArray);
function continueSync() {
// stop the recursion if we have nothing left to process
if (!stuff || stuff.length == 0) return;
// grab the first item off of the stuff queue
v = stuff[0];
stuff = stuff.slice(1);
// call to google
directionsService.route(v, function(result, status) {
var googleLeg = result.routes[0].legs[0];
// sth else...
// now continue processing the rest of the stuff queue through tail recursion
continueSync();
});
}
// kick off our recursive processing
continueSync();
}
your problem is that calling a google service is an asynchronous call, you could prove to generate threads