/*
* polymap.org
* Copyright (C) 2017, the @authors. All rights reserved.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 3.0 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.jgrasstools.gears.libs.modules.multiprocessing;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.Future;
/**
*
*
* @author Falko Bräutigam
*/
public class FixedChunkSizePlanner
extends ExecutionPlanner {
/**
* The absolut upper limit of the chunk size.
*/
public static final int MAX_CHUNK_SIZE = 10000;
private int targetChunkSize = -1;
private List<MultiProcessingTask> accu;
private List<Future> submitted = new ArrayList( 1024 );
private Exception exc;
@Override
public void submit( MultiProcessingTask task ) {
// init targetChunkSize
if (targetChunkSize == -1) {
if (numberOfTasks <= 0) {
throw new IllegalStateException( "No setNumberOfTasks() given." );
}
int procNum = Runtime.getRuntime().availableProcessors();
targetChunkSize = Math.min( numberOfTasks / (procNum*3), MAX_CHUNK_SIZE );
// System.out.println( "targetChunkSize: " + targetChunkSize );
accu = new ArrayList( targetChunkSize );
}
// submit
accu.add( task );
if (accu.size() >= targetChunkSize) {
submitChunk( accu );
accu = new ArrayList( targetChunkSize );
}
}
protected void submitChunk( List<MultiProcessingTask> chunk ) {
// System.out.println( "submitting chunk: size=" + chunk.size() );
// work task
Runnable work = () -> {
try {
//System.out.println( Thread.currentThread().getName() + ": starting..." );
for (MultiProcessingTask task : chunk) {
task.calculate();
}
//System.out.println( Thread.currentThread().getName() + ": chunk done." );
}
catch (Exception e) {
handleException( e );
}
};
// submit
boolean success = false;
for (int waitMillis=10; !success; waitMillis=Math.min( 100, waitMillis*2 ) ) {
// System.out.println( Thread.currentThread().getName() + ": " + taskCount.availablePermits() );
success = submitted.add( defaultExecutor.submit( work ) );
}
}
protected void handleException( Exception e ) {
exc = exc == null ? e : exc;
}
@Override
public void join() throws Exception {
if (exc != null) {
throw exc;
}
if (!accu.isEmpty()) {
submitChunk( accu );
accu = null;
}
for (Future f : submitted) {
try {
f.get();
}
catch (InterruptedException|CancellationException e) {
//
}
}
}
}