package ini.trakem2.parallel;
import ini.trakem2.utils.Utils;
import java.util.Collection;
import java.util.LinkedList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
/** For all methods, if the number of processors given as argument is zero or larger than the maximum available plus 2,
* the number of processors will be adjusted to fall within the range [1, max+2]. */
public class Process {
static private final int MIN_AHEAD = 4;
static public final int NUM_PROCESSORS = Runtime.getRuntime().availableProcessors();
static final int sensible(final int nproc) {
return Math.max(1, Math.min(nproc, NUM_PROCESSORS + 2));
}
/** Takes a Collection of inputs, applies a function to each created by the generator,
* and places their output in outputs in the same order as each input was retrieved from inputs. */
static public final <I,O> void progressive(final Iterable<I> inputs, final TaskFactory<I,O> generator, final Collection<O> outputs) throws Exception {
progressive(inputs, generator, outputs, NUM_PROCESSORS);
}
/** Takes a Collection of inputs, applies a function to each created by the generator,
* and places their output in outputs in the same order as each input was retrieved from inputs. */
static public final <I,O> void progressive(final Iterable<I> inputs, final TaskFactory<I,O> generator, final Collection<O> outputs, final int n_proc) throws Exception {
process(inputs, generator, outputs, n_proc, true);
}
/** Takes a Collection of inputs, applies a function to each created by the generator,
* and places their output in outputs in the same order as each input was retrieved from inputs;
* will not wait for executing tasks to finish before creating and submitting new tasks. */
static public final <I,O> void unbound(final Iterable<I> inputs, final TaskFactory<I,O> generator, final Collection<O> outputs, final int n_proc) throws Exception {
process(inputs, generator, outputs, n_proc, false);
}
static private final <I,O> void process(final Iterable<I> inputs, final TaskFactory<I,O> generator, final Collection<O> outputs, final int n_proc, final boolean bound) throws Exception {
final int nproc = sensible(n_proc);
final ExecutorService exec = Utils.newFixedThreadPool(nproc, "Process." + (bound ? "progressive" : "unbound"));
try {
final LinkedList<Future<O>> fus = new LinkedList<Future<O>>();
final int ahead = Math.max(nproc + nproc, MIN_AHEAD);
for (final I input : inputs) {
if (Thread.currentThread().isInterrupted()) {
return;
}
fus.add(exec.submit(generator.create(input)));
if (bound) while (fus.size() > ahead) {
// wait
outputs.add(fus.removeFirst().get());
}
}
// wait for remaining, if any
for (final Future<O> fu : fus) {
if (null != fu) outputs.add(fu.get());
else outputs.add(null);
}
} finally {
exec.shutdown();
}
}
/** Takes a Collection of inputs, applies a function to each created by the generator. */
static public final <I,O> void progressive(final Iterable<I> inputs, final TaskFactory<I,O> generator) throws Exception {
progressive(inputs, generator, NUM_PROCESSORS);
}
static public final <I,O> void progressive(final Iterable<I> inputs, final TaskFactory<I,O> generator, final int n_proc) throws Exception {
process(inputs, generator, n_proc, true);
}
static public final <I,O> void unbound(final Iterable<I> inputs, final TaskFactory<I,O> generator) throws Exception {
unbound(inputs, generator, NUM_PROCESSORS);
}
static public final <I,O> void unbound(final Iterable<I> inputs, final TaskFactory<I,O> generator, final int n_proc) throws Exception {
process(inputs, generator, n_proc, false);
}
static private final <I,O> void process(final Iterable<I> inputs, final TaskFactory<I,O> generator, final int n_proc, final boolean bound) throws Exception {
final int nproc = sensible(n_proc);
final ExecutorService exec = Utils.newFixedThreadPool(nproc, "Process." + (bound ? "progressive" : "unbound"));
try {
final LinkedList<Future<O>> fus = new LinkedList<Future<O>>();
final int ahead = Math.max(nproc + nproc, MIN_AHEAD);
for (final I input : inputs) {
if (Thread.currentThread().isInterrupted()) {
return;
}
fus.add(exec.submit(generator.create(input)));
if (bound) while (fus.size() > ahead) {
fus.removeFirst().get();
}
}
for (final Future<O> fu : fus) if (null != fu) fu.get();
} finally {
exec.shutdown();
}
}
}