Sorting by Divide-and-Conquer
Divide-and-Conquer in Parallel:
Many computation problems can be solved efficiently by:
int[] arr
of size N
arr
contain 1
?arr
in half1
1
true
if step 1 or 2 succeedsint[] arr
of size N
arr
in increasing orderarr
in halfDivide-and-conquer often lends itself well to parallelism:
Idea:
Creating a Fork-Join Pool is easy!
import java.util.concurrent.ForkJoinPool;
...
ForkJoinPool pool = new ForkJoinPool(POOL_SIZE);
...
pool.invoke(new SomeTask(...));
Tasks without return values = recursive action
RecursiveAction
classcompute()
methodRecursiveAction
import java.util.concurrent.RecursiveAction;
class MSTask extends RecursiveAction {
public MSTask (double[] data, int min, int max) {...}
@Override
protected void compute () {
if (max - min <= 1) {...}
int mid = min + (max - min) / 2
MTask left = new MTask(data, min, mid);
MTask right = new MTask(data, mid, max);
left.fork(); right.fork(); // or can use right.compute()
left.join(); right.join(); // leave out if right.compute()
merge(data, min, mid, max);}}
Invoke with pool.invoke(new MTask(data, 0, data.length))
fork
versus compute
The difference:
fork()
creates new task to be scheduled by the pool
join
compute()
performs computation as part of this task
join
necessaryQuestion. Why use one or the other?
ForkJoinPool
DoesOften Fork-Join pools are not always as efficient you’d like them to be
To deal with this:
Still FJPs can lead to elegant solutions, readable code
What if we want tasks to return a value?
RecursiveTask<T>
!
T
RecursiveAction
except compute()
returns a T
pool.invoke(someRecursiveTask<T>)
now also returns a T
join()
method also returns a T
Finding the maximum value in an unsorted array
Compare the run-times of the two methods!
Download fork-join-pools.zip
PARALLEL_LIMIT
give better performance?fork
/compute
compared to fork
/fork
?Disclaimer:
findMax
efficientlySorting networks!