asynchronous programming in dart (Futures, await) - asynchronous

what changes should I do to the following code to get the following output:
Task 1 complete
Task 4 complete
Task 2 complete
Task 3 complete with task 2 data
I currently getting the outputs given below:
Task 1 complete
Task 2 complete
Task 3 complete with task 2 data
Task 4 complete
import 'dart:async';
void main() {
performTasks();
}
void performTasks() async {
task1();
String task2Result = await task2();
task3(task2Result);
task4();
}
void task1() {
String result = 'task 1 data';
print('Task 1 complete');
}
Future<String> task2() async {
Duration threeSeconds = Duration(seconds: 3);
String result;
await Future.delayed(threeSeconds, () {
result = 'task 2 data';
print('Task 2 complete');
});
return result;
}
void task3(String task2Data) {
String result = 'task 3 data';
print('Task 3 complete with $task2Data');
}
void task4() {
String result = 'task 4 data';
print('Task 4 complete');
}

Don't call task4 after waiting for task2.
So:
void performTasks() async {
task1();
task4();
String task2Result = await task2();
task3(task2Result);
}
That looks pretty obvious, so I'm assuming your real problem is more complicated, and you can't move test4() around like that.
In that case, you should not use await. The await ensures that everything written after the await also executes after the awaited future has completed.
Instead you can fall back on the Future API:
void performTasks() { // no `async`
task1();
task2().then(task3); // no `await`
task4();
}
This sets up task2() to run, and when that is done, it calls task3 with the result. It doesn't wait for anything, though, and it executes task4 immediately after setting this up.
The then method on futures takes a callback, and eventually calls that with the result of the future. Here task3 takes one argument, so it can directly be used as that callback.
That assumes that task2's result is directly usable as an argument to task3. If not, and you have to capture the result and manipulate it first, you'd do it as:
void performTasks() { // no `async`
task1();
task2().then((result2) { // still no await here!
var argument3 = manipulate(result2);
// ... and whatever else you want to do
// between task2 completing and task3 starting.
task3(argument3);
});
task4();
}

in performTasks(), you should move task4(); right after task1();.

Related

Dart waiting for an async function to complete without await

I've narrowed my problem down to the below code. I'm new to Dart, and I can't seem to figure out why the code won't move on to printing "done" before print the numbers 1-10.
import 'dart:async';
Future<bool> wait() async {
for(int i = 0; i < 10; i++){
print('$i');
}
return true;
}
Future testAsync() async {
print('starting');
wait();
print('done');
}
main(List<String> arguments){
testAsync();
}
Since there is no await keyword in front of wait(); shouldn't the program execute print('done'); and then print out the numbers? For some reason, it is waiting for wait(); to finish anyway.
This is expected behavior since Dart 2.0.0:
(Breaking) Functions marked async now run synchronously until the first await statement. Previously, they would return to the event loop once at the top of the function body before any code runs (issue 30345).
https://github.com/dart-lang/sdk/blob/stable/CHANGELOG.md
Since you async method does not actually wait on anything, the entire method is therefore executed synchronously.
You can change you code into something like this to get the behavior your want:
import 'dart:async';
Future<bool> wait() async {
await Future.microtask(() {
for (int i = 0; i < 10; i++) {
print('$i');
}
});
return true;
}
Future testAsync() async {
print('starting');
wait();
print('done');
}
main(List<String> arguments) {
testAsync();
}

Parallel decomposition of independent async tasks with kotlin coroutines

I am trying to run multiple tasks in parallel, but the tasks are independent so if one of children coroutine fails, I do not want its siblings or parent to fail too. In the code below I have used coroutineScope to create a new scope in which these tasks run and launched 5 async tasks each on sending its id and the delay time it should wait. The second coroutine throws an exception. In this case the code does what i want it to do, it calculates the sum of the jobs that successfully finished and the ones that failed return 0.
However, I am reading that there is also supervisorScope in the kotlinx library which should be preferred instead of coroutineScope (which cancels parent/siblings if exception is not handled) for tasks are not dependent on others. I am not sure why I should be changing to use supervisorScope as I am getting the result I want with coroutineScope.
Q1: If i were to change to supervisorScope should something change in my async blocks?
Q2: Is it accepted to catch any exception inside the async block and dont let anything be propagated to its parent? I know you can also catch exceptions during .await() phase but is that the way it should be done?
runBlocking {
coroutineScope {
val job1 = async<Int> {
try {
request(1, 1000)
} catch (e: Exception) {
println("Job 1 failed with $e")
0
}
}
val job2 = async<Int> {
try {
request(2, 2000)
throw Exception("cancelling Job 2")
} catch (e: Exception) {
println("Job 2 failed: $e")
0
}
}
val job3 = async {
try {
request(3, 3000)
} catch (e: Exception) {
println("Job 3 failed with $e")
0
}
}
val job4 = async {
try {
request(4, 4000)
} catch (e: Exception) {
println("Job 4 failed with $e")
0
}
}
val job5 = async {
try {
request(5, 5000)
} catch (e: Exception) {
println("Job 5 failed with $e")
0
}
}
val result = job1.await() + job2.await() + job3.await() + job4.await() + job5.await()
println(result.toString())
}
println("Finished")
}
suspend fun request(id: Int, time: Long): Int {
println("Job $id started")
delay(time)
println("Job $id finished")
return id
}
The reason all coroutines run to completion is that you catch the exception thrown by job 2 within job 2 itself, so it never propagates up the hierarchy of Jobs, so nothing happens.
However, if you remove that catch clause in job2, job[1-5] will always be canceled, independent of if you use coroutineScope or supervisorScope.
This is because job2.await() will throw the exception instead. Since this happens within the parent job of job[1-5] (i.e. within the top coroutineScope/supervisorScope), and since a failed/cancelled parent job always cancel child jobs, job[1-5] will also be cancelled.
A1: Use none of coroutineScope or supervisorScope, remove coroutineScope and put things directly under runBlocking.
A2: It certainly is allowed to catch exceptions within async { } to make sure it doesn't happen in .await() if it fits your use case.

Wrong order of execution in Flutter asynchronous code

I am having problems with futures in a Flutter app.
void saveCats() async {
var cats = await convertToCats(_rawData);
await DatabaseProvider.db.addCats(cats);
}
Future<List<Cat>> convertToCats(CatList catData) async {
var cats = <Cat>[];
await catData.forEach(key, value) async {
var pos = await calculatePos();
print('This should come first');
cats.add(Cat(name: key, pos: pos);
}
}
Future<int> calculatePos() async {
return await DatabaseProvider.db.calculatePos();
}
database.dart:
Future<void> addCats(List<Cat> cats) async {
print('This should come second');
// Do adding stuff here
}
Future<int> calculatePos() async {
// Some code to calculate the position
return pos;
}
In the above code, the saveCats function is called when a button is tapped. This function converts some raw data to a list of Cat models, and adds them to the database. As part of this conversion process, it calculates the pos of the cat in a list. My problem is that I would expect that, of my two print statements, the one in the forEach loop should come before the one in the addCats database function. But instead they appear in reverse order. Where am I going wrong?
You can't async/await in List.forEach() or Map.forEach() as both of them return void.
Either use
await Future.forEach([1, 2, 3], (num) async {
await asyncMethod(num);
});
or something similar;
https://api.flutter.dev/flutter/dart-async/Future/forEach.html
forEach often doesn't do what you expect, because the provided function runs as a closure.
It's more natural when you want to iterate over a list doing something to each element to use for (or one of the more functional type methods like map).
It's not clear what type CatList is, so this is approximate, but you'll want something more like:
Future<List<Cat>> convertToCats(CatList catData) async {
var cats = <Cat>[];
for (var i = 0; i < catData.length; i++) {
var key = catData[i].key;
var pos = await calculatePos();
print('This should come first');
cats.add(Cat(name: key, pos: pos));
}
return cats;
}
or
Future<List<Cat>> convertToCats(CatList catData) async {
return catData.map(...some mapping function...).toList();
}

How to return value from TimerTask in groovy

I'm trying to invoke getStatus method for every 3 seconds and checking am I getting the Done status from my database (remove database code for this testing purpose). Once I got the status "Done" I'm coming out of while loop and I want to return this status to testMethod. But my code is not returning anything back to CompletableFuture. What I'm doing wrong here - can someone please help me to fix this? My code snippet:
CompletableFuture.supplyAsync({ -> getStatus()
}).thenAccept({ status -> testMethod(status) })
def getStatus() {
def response
Timer timer = new Timer()
TimerTask timerTask = new TimerTask(){
#Override
public void run() {
while(true) {
// Doing some DB operation to check the work status is changing to Done and assigning to response
response = "Done"
if (response == "Done") {
timer.cancel()
break;
}
}
}
}
timer.schedule(timerTask, 3000)
return response
}
def testMethod(status) {
System.out.println("testMethod... " +status)
}
The problem is you are scheduling the timer task and then immediately return the current value of response from getStatus(). 3 seconds later or so that task sets the local variable to "Done" but nobody outside the task is looking at that now.
A better approach might be for getStatus itself to return a CompletableFuture. Which the task can populate when it's done.
So something like this:
getStatus().thenAccept({ status -> testMethod(status) })
def getStatus() {
def future = new CompletableFuture<String>()
Timer timer = new Timer()
TimerTask timerTask = new TimerTask(){
#Override
public void run() {
while(true) {
// Doing some DB operation to check the work status is changing to Done and assigning to response
def response = "Done"
if (response == "Done") {
timer.cancel()
future.complete(response)
break;
}
}
}
}
timer.schedule(timerTask, 3000)
return future
}
def testMethod(status) {
System.out.println("testMethod... " +status)
}
EDIT - to add on some kind of timeout you might instead use a ScheduledExecutorService like so:
import java.util.concurrent.*
ScheduledExecutorService executor = Executors.newScheduledThreadPool(2)
getStatus(executor).thenAccept({ status -> testMethod(status) })
def getStatus(executor) {
def future = new CompletableFuture<String>()
def count = 0
def task
def exec = {
println("Running : $count")
// Doing some DB operation to check the work status is changing to Done and assigning to response
def response = "NotDone"
if (response == "Done") {
future.complete(response)
task.cancel()
}
else if (++count == 10) {
future.complete("Failed")
task.cancel()
}
} as Runnable
task = executor.scheduleAtFixedRate(exec, 3, 3, TimeUnit.SECONDS)
future
}
def testMethod(status) {
System.out.println("testMethod... " +status)
}
So I just used an iteration count to stop it running more than 10 times but that could be count or time based. Whatever makes sense for your use case.

Use GPars to dispatch an async task and return immediately

I would like to have a method that dispatches an async task, and returns immediately. I don't need wait for the result.
I'd like something like this to work:
/**
* runs a job and return job id for later montoring.
*/
def int runJob(){
int jobId = createJob() // returns immediately
task{
doSomthingThatTakesSomeTime()
}.then {stepResult-> doSmtgElse(stepResult)}
return jobId
}
In the situation above, the task won't run, as there's no call for .get()
, however, if I DO .get() , the method will not return jobId until task is finished.
How can i dispatch the task and still return immediately?
You can run this example as a Groovy script:
#Grapes(
#Grab(group='org.codehaus.gpars', module='gpars', version='1.2.1')
)
import java.util.concurrent.*
import groovyx.gpars.*
def doSomethingThatTakesSomeTime(){
println "calculating..."
for(long i: 0..100){
Thread.sleep(i)
}
println "*done*"
"Done with doSomethingThatTakesSomeTime"
}
def doSomethingElse(){
for(int x:0..1000) print "."
println "doSomethingElse done."
}
/**
* runs a job and return job id for later montoring.
*/
def runJob(){
GParsPool.withPool(){
Future future = createJob() // returns immediately
doSomethingElse() //Do someting else while the async process is running
//Ok, thats done, but the longer runningprocess is still running, return the future
future
}
}
Future createJob(){
//create a new closure, which starts the original closure on a thread pool
Closure asyncFunction = { doSomethingThatTakesSomeTime() }.async()
//Invoke the function, return a Future
asyncFunction()
}
def job = runJob()
//println "\n\nResult is: " + job.get()
If you run the script "as-is", you will see that it runs and the long running job does print *done* indicating it did in fact run to completion, even though the line at the bottom that calls Future.get() is commented out and never called.
If you uncomment the last line, you will see the result printed once complete as a result of calling Future.get()
After reading #pczeus answer and Jérémie B's comment I came up with this:
import static groovyx.gpars.dataflow.Dataflow.task
def int longTask(){
def counter = 0
10.times {
println "longTask_${counter}"
counter++
sleep 10
}
counter
}
def int getSomeString() {
def jobId=55
task {
longTask()
}.then { num -> println "completed running ${num} times" }
return jobId
}
println getSomeString()
sleep 2000
This prints:
longTask_0
55
longTask_1
longTask_2
longTask_3
longTask_4
longTask_5
longTask_6
longTask_7
longTask_8
longTask_9
completed running 10 times
Which is what I intended:
the longTask() is running in the background, the getSomeString() retruns without waiting for the long task, and as long as the program is still running (hence the sleep 2000), even the clause in the 'then' part is executed

Resources