Use case 1: Serial execution of HTTP calls
Let's say you're building a user interface which depends on two REST services. One provide a list of news article items, while the other is an image hosting service which return image binaries from URL's. The first service returns URL's which are to be used as input for the second service. This makes second operation dependent on the first - they have to be executed serially:
Use case 2: Parallel execution, wait for all
This time the user interface is composed of data from two independent services. You want to display a blank screen with a progress bar only while loading. Only when all data is fetched, you start rendering. This is what I dub the form-merge parallel execution:
Use case 3: Parallel execution, take first
In this case you're firing multiple HTTP queries to identical services, but only care for the response from the first to reply. It might be that you're building a performance-critical application, or you have multiple 3rd-party providers delivering the same service but with varying degree of reliability.
Implementation
Below is listed short examples illustrating the three patterns in the different languages, with support functions in the first chapter. For Java I've chosen to use the RxJava framework simply because that's what I know best. If you know how to do the same with plain Java (8), please let me know or contribute with a pull request to the repo!Support functions
// Resolves the input value after 300ms
function getSlowPromise(returnValue) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(returnValue);
}, 300);
});
}
// Returns input string after 250ms
public static async Task<string> GetSlowStringTask(String toReturn)
{
await Task.Delay(250);
return toReturn;
}
// Returns input int after 250ms
public static async Task<int> GetSlowIntTask(int toReturn)
{
await Task.Delay(250);
return toReturn;
}
suspend fun getSlowStringJob(s: String) : String {
delay(250)
return s
}
suspend fun getSlowIntJob(i: Int) : Int {
delay(250)
return i
}
// Returns the deferred job which completes first
suspend fun <T> awaitFirst(jobs : Array<Deferred<T>>) : Deferred<T> {
var doneJob : Deferred<T>? = null
while (doneJob == null) {
for (job in jobs) {
if (job.isCompleted) {
doneJob = job
break;
}
yield()
}
}
return doneJob
}
Pipeline / Serial execution
// createPromise is a method returning a promise which resolves to the input value
getSlowPromise('job1')
.then((result) => {
return getSlowPromise(result + '-job2');
}).then((result) => {
return getSlowPromise(result + '-job3');
}).then((result) => {
// Result from third job
});
Observable<String> obs1 = Observable.just("Hello world");
obs1.flatMap(s -> {
Observable<Integer> obs2 = Observable.just(s.length());
return obs2;
}).flatMap(i -> {
Observable<String> obs3 = Observable.just("Length: " + i);
return obs3;
}).subscribe(s ->{
System.out.println(s);
// Will output "Length: 11"
});
var str = await GetSlowStringTask("Hello world");
var len = await GetSlowIntTask(str.Length);
var res = await GetSlowStringTask("Len: " + len);
Console.Out.WriteLine(res);
launch(CommonPool) {
val res1 = getSlowStringJob("Hello")
val res2 = getSlowIntJob(res1.length)
val res3 = getSlowStringJob("First string length: " + res2)
System.out.println(res3)
}
Parallel fork-join
// Assuming promise1, 2 and 3 are created
// before this code executing
Promise.all([
promise1,
promise2,
promise3
]).then((results) => {
// 'results' is array of results from each promise
})
// obs1, 2 and 3 are Observable<String>'s
// Assuming each observable only emits 1 value
obs1.mergeWith(obs2)
.mergeWith(obs3)
.buffer(3)
.subscribe(resultArray -> {
// resultArray is String[3]
});
var tasks = new Task<int>[3];
tasks[0] = GetSlowIntTask(1);
tasks[1] = GetSlowIntTask(2);
tasks[2] = GetSlowIntTask(3);
Task.WaitAll(tasks);
for (int i = 0; i < 3; i++)
{
Console.Out.WriteLine("Res " + i + ": " + tasks[i].Result);
}
val job1 = async(CommonPool) { getSlowIntJob(1) }
val job2 = async(CommonPool) { getSlowIntJob(2) }
val job3 = async(CommonPool) { getSlowIntJob(3) }
launch(CommonPool) {
val sum = job1.await() + job2.await() + job3.await()
System.out.println("Sum: " + sum)
}
Parallel take first
Promise.race([
promise1,
promise2,
promise3
]).then((result) => {
// result is first to return
})
// obs1, 2 and 3 are Observable<String>'s
// Assuming each observable only emits 1 value
obs1.mergeWith(obs2)
.mergeWith(obs3)
.first()
.subscribe(result -> {
// result is String
});
var tasks = new Task<int>[3];
tasks[0] = GetSlowIntTask(1);
tasks[1] = GetSlowIntTask(2);
tasks[2] = GetSlowIntTask(3);
int firstResult = Task.WaitAny(tasks);
Console.Out.WriteLine("Res " + firstResult);
val job1 = async(CommonPool) { getSlowIntJob(1) }
val job2 = async(CommonPool) { getSlowIntJob(2) }
val job3 = async(CommonPool) { getSlowIntJob(3) }
launch(CommonPool) {
val jobs = arrayOf(job1, job2, job3)
val first = awaitFirst(jobs)
System.out.println("Finished first: " + first.getCompleted())
}
Thanks to Espen Volden for contributing with Javascript examples
Article updated 18 Feb 2017 with Kotlin 1.1 Coroutines examples
Free Quilting Patterns and Free Quilting Blocks from WinddancerCreations. Hundreds of quilting patterns to choose from! animal quilt patterns
ReplyDeleteGreat Article
DeleteFInal Year Project Centers in Chennai
JavaScript Training in Chennai
JavaScript Training in Chennai
Hats off to your presence of mind..I really enjoyed reading your blog. I really appreciate your information which you shared with us.
ReplyDeletePhp course in chennai
Thanks a lot
ReplyDeleteInteresting! I’ve never worked with Async. But while studying in university I had to do Python project. It was a dreadful nightmare for me cause programming is not my cup of tea. But thanks to https://www.assignmentexpert.com/programming/python I nailed it. They explained me basic principles of its work and helped me with project. Hope it will be useful for you.
ReplyDeleteAwesome blog. I would love to see true life prepared to walk, so please share more informative updates. Great work keeps it up. hostgator coupons
ReplyDeleteHi Thanks for the nice information its very useful to read your blog.
ReplyDeleteAdvanced SEO Training
Kanhasoft is leading Django Application Development Company in India and USA. We have a team of 45+ experienced Django developers to outsource our services. You can visit our site for more information.
ReplyDeleteNew languages and dialect expansions are being created to expand the ease of use of the Internet once a day. easy programming class Livermore
ReplyDeleteGreat Article
ReplyDeleteFinal Year Projects for CSE in Python
FInal Year Project Centers in Chennai
JavaScript Training in Chennai
JavaScript Training in Chennai
The post you wrote which is full of informative content. I Like it very much. Keep on posting!!
ReplyDeleteAngularjs Training in Chennai
Angularjs course in Chennai
Big Data Training in Chennai
German Classes in Chennai
AngularJS Training in Porur
AngularJS Training in Velachery
AngularJS Training in Adyar
This comment has been removed by the author.
ReplyDeleteGo to the online casino and earn now slot on line casino Everyone has a chance to win and you are my friend is no exception, go to BGAOC and win.
ReplyDelete