package whitebox.parallel;
/**
* Java Parallel.For Parallel.ForEach Parallel.Tasks
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.Future;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ExecutionException;
/**
* A Java Parallel for SMP
*
* [24-Jan-13] This class is under development and its parallel methods should
* be used with caution, if at all. In the near term, it is chiefly being used
* to provide a place where plugins with parallel algorithms may find out how
* many processors to use (e.g., how many threads to create). That limit is
* managed by the Timing Profiler window that can be popped up from the main
* GUI's Tools menu. Ordinary users will not care to use this tool, thus
* parallelized plugins will utilize all available processors by default.
*/
public class Parallel {
static int iCPU = Runtime.getRuntime().availableProcessors();
/*
* The get method is for plugins with adjustable parallelism to find the
* no. of processors that they should use at run time.
*/
public static int getPluginProcessors() {
return iCPU;
}
/*
* The set method is for use by Timing Profiler, so it can limit the no.
* of processors for plugins to use for the purpose of timing tests.
*/
public static void setPluginProcessors(int iCPU) {
Parallel.iCPU = iCPU;
}
/**
* Parallel.Tasks
*/
public static void Tasks(final Task[] tasks) {
ExecutorService executor = Executors.newFixedThreadPool(iCPU);
ArrayList<Future<?>> futures = new ArrayList<>();
for (final Task task : tasks) {
Future<?> future = executor.submit(new Runnable() {
@Override
public void run() {
task.run();
}
});
futures.add(future);
}
for (Future<?> f : futures) {
try {
f.get();
} catch (InterruptedException e) {
} catch (ExecutionException e) {
}
}
executor.shutdown();
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
}
}
/**
* Parallel.ForEach
* This method using a blocking Callable form of the loopBody and therefore
* will complete all assigned tasks before continuing.
*/
public static <T> void ForEach(Iterable<T> parameters, final CallableLoopBody<T> loopBody) {
ExecutorService executor = Executors.newFixedThreadPool(iCPU);
ArrayList<Callable<Boolean>> tasks = new ArrayList<>();
for (final T param : parameters) {
tasks.add(new Callable() {
@Override
public Boolean call() {
return loopBody.call(param);
}
});
}
int success = 0;
int failure = 0;
try {
List<Future<Boolean>> futures = executor.invokeAll(tasks);
for (Future<Boolean> fut : futures) {
int ignore = fut.get() ? success++ : failure++;
}
} catch (InterruptedException | ExecutionException e) {
} finally {
executor.shutdown();
}
}
/**
* Parallel.ForEach
*/
public static <T> void ForEach(Iterable<T> parameters, final LoopBody<T> loopBody) {
ExecutorService executor = Executors.newFixedThreadPool(iCPU);
ArrayList<Future<?>> futures = new ArrayList<>();
for (final T param : parameters) {
Future<?> future = executor.submit(new Runnable() {
@Override
public void run() {
loopBody.run(param);
}
});
futures.add(future);
}
for (Future<?> f : futures) {
try {
f.get();
} catch (InterruptedException e) {
} catch (ExecutionException e) {
}
}
executor.shutdown();
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
// System.out.println("Executor terminated status: " + executor.isTerminated());
} catch (InterruptedException e) {
}
}
/**
* Parallel.For
*/
public static void For(int start, int end, int step, final LoopBody<Integer> loopBody) {
ExecutorService executor = Executors.newFixedThreadPool(iCPU);
ArrayList<Future<?>> futures = new ArrayList<>();
ArrayList<Partition> partitions = create(start, end, iCPU);
for (final Partition p : partitions) {
Future<?> future = executor.submit(new Runnable() {
@Override
public void run() {
for (int i = p.start; i < p.end; i++) {
loopBody.run(i);
}
}
});
futures.add(future);
}
for (Future<?> f : futures) {
try {
f.get();
} catch (InterruptedException e) {
} catch (ExecutionException e) {
}
}
executor.shutdown();
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
}
}
/**
* Create Partitions To Turn Parallel.For To Parallel.ForEach
*/
public static ArrayList<Partition> create(int inclusiveStart, int exclusiveEnd) {
return create(inclusiveStart, exclusiveEnd, iCPU);
}
public static ArrayList<Partition> create(int inclusiveStart, int exclusiveEnd, int cores) {
//increment
int total = exclusiveEnd - inclusiveStart;
// for (int a = inclusiveStart; a < exclusiveEnd; a += step) {
// total++;
// }
double dc = (double) total / cores;
int ic = (int) dc;
if (ic <= 0) {
ic = 1;
}
if (dc > ic) {
ic++;
}
//partitions
ArrayList<Partition> partitions = new ArrayList<>();
if (total <= cores) {
for (int i = inclusiveStart; i < exclusiveEnd; i++) {
Partition p = new Partition();
p.start = i;
p.end = i + 1;
//p.step = step;
partitions.add(p);
}
return partitions;
}
int count = inclusiveStart;
while (count < exclusiveEnd) {
Partition p = new Partition();
p.start = count;
p.end = count + ic;
//p.step = step;
partitions.add(p);
count += ic;
//boundary check
if (p.end >= exclusiveEnd) {
p.end = exclusiveEnd;
break;
}
}
return partitions;
}
/**
* Unit Test
*/
public static void main(String[] argv) {
//sample data
final ArrayList<String> ss = new ArrayList<>();
String[] s = {"a", "b", "c", "d", "e", "f", "g"};
ss.addAll(Arrays.asList(s));
int m = ss.size();
Parallel.For(13, 20, 1, new LoopBody<Integer>() {
@Override
public void run(Integer i) {
System.out.println(i);
}
});
//parallel-for loop
System.out.println("Parallel.For loop:");
Parallel.For(2, m, 1, new LoopBody<Integer>() {
@Override
public void run(Integer i) {
System.out.println(i + "\t" + ss.get(i));
}
});
// //parallel for-each loop
// System.out.println("Parallel.ForEach loop:");
// Parallel.ForEach(ss, new LoopBody<String>() {
//
// @Override
// public void run(String p) {
// System.out.println(p);
// }
// });
//
// //partitioned parallel loop
// System.out.println("Partitioned Parallel loop:");
// Parallel.ForEach(Parallel.create(0, m), new LoopBody<Partition>() {
//
// @Override
// public void run(Partition p) {
// for (int i = p.start; i < p.end; i++) {
// System.out.println(i + "\t" + ss.get(i));
// }
// }
// });
//
// //parallel tasks
// System.out.println("Parallel Tasks:");
// Parallel.Tasks(new Task[]{
// //task-1
// new Task() {
//
// @Override
// public void run() {
// for (int i = 0; i < 3; i++) {
// System.out.println(i + "\t" + ss.get(i));
// }
// }
// },
// //task-2
// new Task() {
//
// @Override
// public void run() {
// for (int i = 3; i < 6; i++) {
// System.out.println(i + "\t" + ss.get(i));
// }
// }
// }
// });
}
}