/* * Encog(tm) Core v3.4 - Java Version * http://www.heatonresearch.com/encog/ * https://github.com/encog/encog-java-core * Copyright 2008-2016 Heaton Research, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * For more information on Heaton Research copyrights, licenses * and trademarks visit: * http://www.heatonresearch.com/copyright */ package org.encog.util.concurrency; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.encog.EncogError; /** * This class abstracts thread pools, and potentially grids and other types of * concurrency. It is used by other classes inside of Encog to allow tasks to be * executed efficiently on multicore machines. * * @author jheaton * */ public class EngineConcurrency implements MultiThreadable { /** * Singleton instance. */ private static EngineConcurrency instance = new EngineConcurrency(); /** * @return The instance to the singleton. */ public static EngineConcurrency getInstance() { return EngineConcurrency.instance; } /** * An error that was caught in one of the threads. Will be thrown by the * main thread. */ private Throwable threadError; /** * The thread count. */ private int threadCount; /** * The current task group, used to ensure that all threads finish at the * same time. */ private int currentTaskGroup; /** * The executor service we are using. */ private ExecutorService executor; /** * Construct a concurrency object. */ public EngineConcurrency() { Runtime runtime = Runtime.getRuntime(); int threads = runtime.availableProcessors(); // NOTE: This was tested on a Intel i7 4 cores 8 threads with // Encog Benchmark. Ca 15% higher performance with exactly 8 threads. // if( threads>1 ) // threads++; this.executor = Executors.newFixedThreadPool(threads); } /** * {@inheritDoc} */ @Override public void setThreadCount(int t) { if (this.executor != null) { this.executor.shutdown(); int threads = t; if (threads == 0) { Runtime runtime = Runtime.getRuntime(); threads = runtime.availableProcessors(); if (threads > 1) threads++; } this.executor = Executors.newFixedThreadPool(threads); this.threadCount = threads; } } /** * Check to see if one of the threads has thrown an error. If so, then throw * that error. */ public void checkError() { if (this.threadError != null) { throw new EncogError(this.threadError); } } /** * Create a new task group. * * @return The new task group. */ public TaskGroup createTaskGroup() { TaskGroup result = null; synchronized (this) { this.currentTaskGroup++; result = new TaskGroup(this.currentTaskGroup); } return result; } /** * Process the specified task. * * @param task * The task to process. */ public void processTask(final EngineTask task) { processTask(task, null); } /** * Process the specified task. It will be processed either now, or queued to * process on the thread pool. * * @param task * The task to process. * @param group * The task group. */ public void processTask(final EngineTask task, final TaskGroup group) { if (this.executor == null) { task.run(); } else { if (this.threadError != null) { final Throwable t = this.threadError; this.threadError = null; throw new EncogError(t); } final PoolItem item = new PoolItem(task, group); if (group != null) { group.taskStarting(); } this.executor.execute(item); } } /** * Allows threads to register errors, these errors will be thrown by the * main thread. * * @param t * The error to register. */ public void registerError(final Throwable t) { synchronized (this) { this.threadError = t; } } /** * Wait for all threads in the pool to complete. * * @param timeout * How long to wait for all threads to complete. */ public void shutdown(final long timeout) { if (this.executor != null) { try { this.executor.shutdown(); this.executor.awaitTermination(timeout, TimeUnit.SECONDS); this.executor = null; } catch (final InterruptedException e) { throw new EncogError(e); } } } /** * {@inheritDoc} */ @Override public int getThreadCount() { return this.threadCount; } }