package edu.stanford.rsl.conrad.parallel; import ij.IJ; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import edu.stanford.rsl.conrad.utils.CONRAD; /** * Class to execute multiple ParallelizeableRunnables in parallel. The Executor will dispatch * as many ParallelizedRunnables as there are CPUs in the machine on which the code is executed in one batch. * Then it will wait until all processes in the current batch are done. As soon as this is the case a new batch * of processes is started. This is done until all ParallelizableRunnables are processed. * * @author Andreas Maier * */ public class ParallelThreadExecutor { private boolean showStatus; ParallelizableRunnable [] runnables; boolean debug = false; private CountDownLatch latch; public static boolean parallel = true; public void setShowStatus(boolean showStatus) { this.showStatus = showStatus; } public boolean isShowStatus() { return showStatus; } /** * In order to have the threads performed in parallel just an Array of ParallelizableRunnables is * passed to the contructor of the ParallelThreadExecutor. * @param runnables the processes to run. */ public ParallelThreadExecutor(ParallelizableRunnable [] runnables){ this.runnables = runnables; } public ParallelThreadExecutor(ParallelizableRunnable [] runnables, int latchSize){ this.runnables = runnables; latch = new CountDownLatch(latchSize); } /** * This method will start the processing. * @throws InterruptedException may occur. */ public void execute() throws InterruptedException{ int numThreads = CONRAD.getNumberOfThreads(); if (showStatus) CONRAD.log("Number of used processors: " + numThreads); if (numThreads > 7) if (showStatus) CONRAD.log("I like this machine ... "); Future <?> [] futures = new Future<?>[runnables.length]; if (debug) System.out.println("Starting new batch ..."); ExecutorService e = Executors.newFixedThreadPool(numThreads); // initialize the parallel processing. long latchSize = 0; if(latch == null) { latch = new CountDownLatch(runnables.length); latchSize = runnables.length; } else { latchSize = latch.getCount(); } if (parallel) { parallel = false; // invoke the threads for (int i = 0; i < runnables.length; i++){ runnables[i].setLatch(latch); futures[i] = e.submit(runnables[i]); } // wait for all jobs to be done while (latch.getCount() > 0){ if (showStatus){ int i = (int) (latchSize - latch.getCount()); if (i < runnables.length){ if (runnables[i] instanceof NamedParallelizableRunnable)IJ.showStatus("Running " + ((NamedParallelizableRunnable)runnables[i]).getProcessName()); } IJ.showProgress((i + 0.0) / latchSize); } Thread.sleep(CONRAD.INVERSE_SPEEDUP); } e.awaitTermination(1000, TimeUnit.MILLISECONDS);//e.shutdownNow(); e = null; if (showStatus) IJ.showProgress(1.0); parallel = true; } else { //System.out.println("Debug mode. Invoking sequentially."); for (int i = 0; i < runnables.length; i++){ runnables[i].setLatch(latch); //System.out.println("Thread " + i); runnables[i].run(); } //System.out.println("All done."); } } } /* * Copyright (C) 2010-2014 Andreas Maier * CONRAD is developed as an Open Source project under the GNU General Public License (GPL). */