+ * By default, the engine uses the {@link ForkJoinPool#commonPool()} for
+ * executing the evolution steps and evaluating the fitness function concurrently.
+ * You can change the used execution services with the {@link Builder#executor(Executor)}
+ * method. If you want to use a different executor for evaluating the fitness
+ * functions, you have to set the {@link Builder#batchExecutor(BatchExecutor)}.
+ *
+ *
{@code
+ * final Engine engine = Engine
+ * .builder(...)
+ * // Using this execution service for parallelize the evolution steps.
+ * .executor(Executors.newFixedThreadPool(5))
+ * // Using one virtual thread for every fitness function evaluation.
+ * .batchExecutor(BatchExecutor.ofVirtualThreads())
+ * .build();
+ * }
+ *
* @implNote
* This class is thread safe: The engine maintains no mutable state.
* Therefore, it is safe to create multiple evolution streams with one
@@ -590,7 +608,10 @@ Builder builder(
final Function super Genotype, ? extends C> ff,
final Factory> gtf
) {
- return new Builder<>(Evaluators.ofVirtualThread(ff), gtf);
+ return new Builder<>(
+ new FitnessEvaluator<>(ff, BatchExecutor.of(commonPool())),
+ gtf
+ );
}
/**
@@ -696,6 +717,7 @@ public static final class Builder<
// Engine execution environment.
private Executor _executor = commonPool();
+ private BatchExecutor _batchExecutor = null;
private InstantSource _clock = NanoClock.systemUTC();
private EvolutionInterceptor _interceptor =
@@ -714,14 +736,14 @@ public static final class Builder<
* @see Engine#builder(Function, Chromosome, Chromosome[])
*
* @param evaluator the fitness evaluator
- * @param genotypeFactory the genotype factory
+ * @param gtf the genotype factory
* @throws NullPointerException if one of the arguments is {@code null}.
*/
public Builder(
final Evaluator evaluator,
- final Factory> genotypeFactory
+ final Factory> gtf
) {
- _genotypeFactory = requireNonNull(genotypeFactory);
+ _genotypeFactory = requireNonNull(gtf);
_evaluator = requireNonNull(evaluator);
}
@@ -853,7 +875,7 @@ public Builder optimize(final Optimize optimize) {
}
/**
- * Set to a fitness maximizing strategy.
+ * Set to a fitness-maximizing strategy.
*
* @since 3.4
*
@@ -982,6 +1004,10 @@ public Builder maximalPhenotypeAge(final long age) {
/**
* The executor used by the engine.
*
+ * @apiNote
+ * If no dedicated {@link Evaluator} is defined, this is also the
+ * executor, used for evaluating the fitness functions.
+ *
* @param executor the executor used by the engine
* @return {@code this} builder, for command chaining
*/
@@ -990,6 +1016,23 @@ public Builder executor(final Executor executor) {
return this;
}
+ /**
+ * This executor is used for evaluating the fitness functions.
+ *
+ * @apiNote
+ * If a dedicated {@link Evaluator} is defined, this executor is not
+ * used.
+ *
+ * @since !__version__!
+ *
+ * @param executor the executor used for evaluating the fitness functions
+ * @return {@code this} builder, for command chaining
+ */
+ public Builder batchExecutor(final BatchExecutor executor) {
+ _batchExecutor = requireNonNull(executor);
+ return this;
+ }
+
/**
* The clock used for calculating the execution durations.
*
@@ -1038,8 +1081,8 @@ public Engine build() {
}
private Evaluator __evaluator() {
- return _evaluator instanceof ExecutorEvaluator ce
- ? ce.with(_executor)
+ return _evaluator instanceof FitnessEvaluator fe
+ ? new FitnessEvaluator<>(fe.function(), batchExecutor())
: _evaluator;
}
@@ -1086,6 +1129,19 @@ public Executor executor() {
return _executor;
}
+ /**
+ * Return the batch executor, used for evaluating the fitness functions.
+ *
+ * @since !__version__!
+ *
+ * @return the batch executor, used for evaluating the fitness functions
+ */
+ public BatchExecutor batchExecutor() {
+ return _batchExecutor != null
+ ? _batchExecutor
+ : BatchExecutor.of(executor());
+ }
+
/**
* Return the used genotype {@link Factory} of the GA. The genotype factory
* is used for creating the initial population and new, random individuals
diff --git a/jenetics/src/main/java/io/jenetics/engine/Evaluators.java b/jenetics/src/main/java/io/jenetics/engine/Evaluators.java
index 928717da1f..bd833e5503 100644
--- a/jenetics/src/main/java/io/jenetics/engine/Evaluators.java
+++ b/jenetics/src/main/java/io/jenetics/engine/Evaluators.java
@@ -20,217 +20,27 @@
package io.jenetics.engine;
import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.function.Function;
import io.jenetics.Gene;
import io.jenetics.Genotype;
import io.jenetics.internal.concurrent.CompletableFutureEvaluator;
-import io.jenetics.internal.concurrent.ExecutorEvaluator;
import io.jenetics.internal.concurrent.FutureEvaluator;
-import io.jenetics.internal.concurrent.VirtualThreadEvaluator;
/**
* This class contains factory methods for creating commonly usable
- * {@link Evaluator} implementations. By default, the evolution {@link Engine}
- * uses the {@code concurrent} evaluators ({@link #concurrent(Function, Executor)}).
+ * {@link Evaluator} implementations.
*
* @see Evaluator
*
* @author Franz Wilhelmstötter
- * @version 5.0
+ * @version !__version__!
* @since 5.0
*/
public final class Evaluators {
private Evaluators() {}
- /**
- * Return a new fitness evaluator, which evaluates the fitness function of
- * the population serially in the main thread. Might be useful for testing
- * purpose.
- *
- * @param fitness the fitness function
- * @param the gene type
- * @param the fitness value type
- * @return a new serial fitness evaluator
- * @throws NullPointerException if the fitness {@code function} is {@code null}
- */
- public static , C extends Comparable super C>>
- Evaluator
- serial(final Function super Genotype, ? extends C> fitness) {
- return concurrent(fitness, Runnable::run);
- }
-
- /**
- * Return a new fitness evaluator, which evaluates the fitness function of
- * the population serially in the main thread. Might be useful for testing
- * purpose.
- *
- * @param fitness the fitness function
- * @param decoder the decoder function for the fitness domain
- * @param the native fitness domain type
- * @param the gene type
- * @param the fitness value type
- * @return a new (concurrent) fitness evaluator
- * @throws NullPointerException if one of the arguments is {@code null}
- */
- public static , C extends Comparable super C>>
- Evaluator serial(
- final Function super T, ? extends C> fitness,
- final Function super Genotype, ? extends T> decoder
- ) {
- return serial(fitness.compose(decoder));
- }
-
- /**
- * Return a new fitness evaluator, which evaluates the fitness function of
- * the population serially in the main thread. Might be useful for testing
- * purpose.
- *
- * @param fitness the fitness function
- * @param codec the codec used for transforming the fitness domain
- * @param the native fitness domain type
- * @param the gene type
- * @param the fitness value type
- * @return a new (concurrent) fitness evaluator
- * @throws NullPointerException if one of the arguments is {@code null}
- */
- public static , C extends Comparable super C>>
- Evaluator serial(
- final Function super T, ? extends C> fitness,
- final Codec codec
- ) {
- return serial(fitness.compose(codec.decoder()));
- }
-
- /**
- * Return a new fitness evaluator, which evaluates the fitness function
- * using one virtual thread per fitness function.
- *
- * @param fitness the fitness function
- * @param the gene type
- * @param the fitness value type
- * @return a new serial fitness evaluator
- * @throws NullPointerException if the fitness {@code function} is {@code null}
- */
- public static , C extends Comparable super C>>
- Evaluator
- ofVirtualThread(final Function super Genotype, ? extends C> fitness) {
- return new VirtualThreadEvaluator<>(fitness);
- }
-
- /**
- * Return a new fitness evaluator, which evaluates the fitness function
- * using one virtual thread per fitness function.
- *
- * @param fitness the fitness function
- * @param codec the codec used for transforming the fitness domain
- * @param the native fitness domain type
- * @param the gene type
- * @param the fitness value type
- * @return a new (concurrent) fitness evaluator
- * @throws NullPointerException if one of the arguments is {@code null}
- */
- public static , C extends Comparable super C>>
- Evaluator ofVirtualThread(
- final Function super T, ? extends C> fitness,
- final Codec codec
- ) {
- return ofVirtualThread(fitness.compose(codec.decoder()));
- }
-
- /**
- * Return a new fitness evaluator, which evaluates the fitness function
- * using one virtual thread per fitness function.
- *
- * @param fitness the fitness function
- * @param decoder the decoder function for the fitness domain
- * @param the native fitness domain type
- * @param the gene type
- * @param the fitness value type
- * @return a new (concurrent) fitness evaluator
- * @throws NullPointerException if one of the arguments is {@code null}
- */
- public static , C extends Comparable super C>>
- Evaluator ofVirtualThread(
- final Function super T, ? extends C> fitness,
- final Function super Genotype, ? extends T> decoder
- ) {
- return ofVirtualThread(fitness.compose(decoder));
- }
-
- /**
- * Return a new fitness evaluator, which evaluates the fitness function of
- * the population (concurrently) with the given {@code executor}. This is
- * the default evaluator used by the evolution engine.
- *
- * @param fitness the fitness function
- * @param executor the {@code Executor} used for evaluating the fitness
- * function
- * @param the gene type
- * @param the fitness value type
- * @return a new (concurrent) fitness evaluator
- * @throws NullPointerException if one of the arguments is {@code null}
- */
- public static , C extends Comparable super C>>
- Evaluator concurrent(
- final Function super Genotype, ? extends C> fitness,
- final Executor executor
- ) {
- return new ExecutorEvaluator<>(fitness, executor);
- }
-
- /**
- * Return a new fitness evaluator, which evaluates the fitness function of
- * the population (concurrently) with the given {@code executor}. This is
- * the default evaluator used by the evolution engine.
- *
- * @param fitness the fitness function, working on the native
- * fitness domain
- * @param decoder the decoder function for the fitness domain
- * @param executor the {@code Executor} used for evaluating the fitness
- * function
- * @param the native fitness domain type
- * @param the gene type
- * @param the fitness value type
- * @return a new (concurrent) fitness evaluator
- * @throws NullPointerException if one of the arguments is {@code null}
- */
- public static , C extends Comparable super C>>
- Evaluator concurrent(
- final Function super T, ? extends C> fitness,
- final Function super Genotype, ? extends T> decoder,
- final Executor executor
- ) {
- return concurrent(fitness.compose(decoder), executor);
- }
-
- /**
- * Return a new fitness evaluator, which evaluates the fitness function of
- * the population (concurrently) with the given {@code executor}. This is
- * the default evaluator used by the evolution engine.
- *
- * @param fitness the fitness function, working on the native
- * fitness domain
- * @param codec the codec used for transforming the fitness domain
- * @param executor the {@code Executor} used for evaluating the fitness
- * function
- * @param the native fitness domain type
- * @param the gene type
- * @param the fitness value type
- * @return a new (concurrent) fitness evaluator
- * @throws NullPointerException if one of the arguments is {@code null}
- */
- public static , C extends Comparable super C>>
- Evaluator concurrent(
- final Function super T, ? extends C> fitness,
- final Codec codec,
- final Executor executor
- ) {
- return concurrent(fitness, codec.decoder(), executor);
- }
-
/**
* Return a new fitness evaluator, which evaluates asynchronous
* fitness functions.
diff --git a/jenetics/src/main/java/io/jenetics/internal/concurrent/AbstractEvaluator.java b/jenetics/src/main/java/io/jenetics/engine/FitnessEvaluator.java
similarity index 78%
rename from jenetics/src/main/java/io/jenetics/internal/concurrent/AbstractEvaluator.java
rename to jenetics/src/main/java/io/jenetics/engine/FitnessEvaluator.java
index 1c85ee45cb..c215167b19 100644
--- a/jenetics/src/main/java/io/jenetics/internal/concurrent/AbstractEvaluator.java
+++ b/jenetics/src/main/java/io/jenetics/engine/FitnessEvaluator.java
@@ -17,7 +17,7 @@
* Author:
* Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
*/
-package io.jenetics.internal.concurrent;
+package io.jenetics.engine;
import static java.util.Objects.requireNonNull;
@@ -26,7 +26,8 @@
import io.jenetics.Gene;
import io.jenetics.Genotype;
import io.jenetics.Phenotype;
-import io.jenetics.engine.Evaluator;
+import io.jenetics.internal.concurrent.RunnableFunction;
+import io.jenetics.util.BatchExecutor;
import io.jenetics.util.ISeq;
import io.jenetics.util.Seq;
@@ -38,28 +39,30 @@
* @version !__version__!
* @since !__version__!
*/
-public abstract class AbstractEvaluator<
+public final class FitnessEvaluator<
G extends Gene, G>,
C extends Comparable super C>
>
- implements FitnessEvaluator
+ implements Evaluator
{
- protected final Function super Genotype, ? extends C> _function;
+ private final Function super Genotype, ? extends C> _function;
+ private final BatchExecutor _executor;
- protected AbstractEvaluator(
- final Function super Genotype, ? extends C> function
+ public FitnessEvaluator(
+ final Function super Genotype, ? extends C> function,
+ final BatchExecutor executor
) {
_function = requireNonNull(function);
+ _executor = requireNonNull(executor);
}
- @Override
public Function super Genotype, ? extends C> function() {
return _function;
}
@Override
- public final ISeq> eval(final Seq> population) {
+ public ISeq> eval(final Seq> population) {
final var tasks = population.stream()
.filter(Phenotype::nonEvaluated)
.map(phenotype -> new RunnableFunction<>(
@@ -70,7 +73,7 @@ public final ISeq> eval(final Seq> population) {
final ISeq> result;
if (tasks.nonEmpty()) {
- execute(tasks);
+ _executor.execute(tasks);
result = tasks.size() == population.size()
? tasks.map(t -> t.input().withFitness(t.result()))
@@ -84,7 +87,4 @@ public final ISeq> eval(final Seq> population) {
return result;
}
-
- protected abstract void execute(final Seq extends Runnable> tasks);
-
}
diff --git a/jenetics/src/main/java/io/jenetics/internal/concurrent/BatchExecutor.java b/jenetics/src/main/java/io/jenetics/internal/concurrent/BatchExec.java
similarity index 85%
rename from jenetics/src/main/java/io/jenetics/internal/concurrent/BatchExecutor.java
rename to jenetics/src/main/java/io/jenetics/internal/concurrent/BatchExec.java
index d8f4c4cb56..9a5c163bdd 100644
--- a/jenetics/src/main/java/io/jenetics/internal/concurrent/BatchExecutor.java
+++ b/jenetics/src/main/java/io/jenetics/internal/concurrent/BatchExec.java
@@ -27,10 +27,10 @@
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
-import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
+import io.jenetics.util.BatchExecutor;
import io.jenetics.util.Seq;
/**
@@ -38,17 +38,17 @@
* @version !__version__!
* @since 2.0
*/
-class BatchExecutor implements AutoCloseable {
+public class BatchExec implements BatchExecutor {
public static final int CORES = Runtime.getRuntime().availableProcessors();
- final List> _futures = new ArrayList<>();
final Executor _executor;
- BatchExecutor(final Executor executor) {
+ public BatchExec(final Executor executor) {
_executor = requireNonNull(executor);
}
+ @Override
public void execute(final Seq extends Runnable> batch) {
if (batch.nonEmpty()) {
final int[] parts = partition(
@@ -59,41 +59,28 @@ public void execute(final Seq extends Runnable> batch) {
)
);
+ final var futures = new ArrayList>();
for (int i = 0; i < parts.length - 1; ++i) {
- execute(new BatchRunnable(batch, parts[i], parts[i + 1]));
+ execute(
+ new BatchRunnable(batch, parts[i], parts[i + 1]),
+ futures
+ );
}
+
+ Futures.join(futures);
}
}
- private void execute(final Runnable command) {
+ private void execute(final Runnable command, final List> futures) {
if (_executor instanceof ExecutorService service) {
- _futures.add(service.submit(command));
+ futures.add(service.submit(command));
} else {
final FutureTask> task = new FutureTask<>(command, null);
- _futures.add(task);
+ futures.add(task);
_executor.execute(task);
}
}
- @Override
- public void close() {
- Futures.join(_futures);
- }
-
- /**
- * Return a new Concurrency object from the given executor.
- *
- * @param executor the underlying Executor
- * @return a new Concurrency object
- */
- public static BatchExecutor with(final Executor executor) {
- if (executor instanceof ForkJoinPool e) {
- return new BatchForkJoinPool(e);
- } else {
- return new BatchExecutor(executor);
- }
- }
-
/**
* Return an array with the indexes of the partitions of an array with the
* given size. The length of the returned array is {@code min(size, prts) + 1}.
diff --git a/jenetics/src/main/java/io/jenetics/internal/concurrent/BatchForkJoinPool.java b/jenetics/src/main/java/io/jenetics/internal/concurrent/BatchForkJoinPool.java
index 436882e241..ee3aee4353 100644
--- a/jenetics/src/main/java/io/jenetics/internal/concurrent/BatchForkJoinPool.java
+++ b/jenetics/src/main/java/io/jenetics/internal/concurrent/BatchForkJoinPool.java
@@ -19,7 +19,9 @@
*/
package io.jenetics.internal.concurrent;
+import java.util.ArrayList;
import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.Future;
import io.jenetics.util.Seq;
@@ -30,11 +32,10 @@
* @version !__version__!
* @since 2.0
*/
-final class BatchForkJoinPool extends BatchExecutor {
+public final class BatchForkJoinPool extends BatchExec {
- BatchForkJoinPool(final ForkJoinPool pool) {
+ public BatchForkJoinPool(final ForkJoinPool pool) {
super(pool);
-
}
@Override
@@ -43,7 +44,9 @@ public void execute(final Seq extends Runnable> batch) {
final var future = ((ForkJoinPool)_executor)
.submit(new BatchAction(batch));
- _futures.add(future);
+ final var futures = new ArrayList>();
+ futures.add(future);
+ Futures.join(futures);
}
}
diff --git a/jenetics/src/main/java/io/jenetics/internal/concurrent/ExecutorEvaluator.java b/jenetics/src/main/java/io/jenetics/internal/concurrent/ExecutorEvaluator.java
deleted file mode 100644
index 92e200ad2c..0000000000
--- a/jenetics/src/main/java/io/jenetics/internal/concurrent/ExecutorEvaluator.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Java Genetic Algorithm Library (@__identifier__@).
- * Copyright (c) @__year__@ Franz Wilhelmstötter
- *
- * 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.
- *
- * Author:
- * Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
- */
-package io.jenetics.internal.concurrent;
-
-import static java.util.Objects.requireNonNull;
-
-import java.util.concurrent.Executor;
-import java.util.function.Function;
-
-import io.jenetics.Gene;
-import io.jenetics.Genotype;
-import io.jenetics.util.Seq;
-
-/**
- * Default phenotype evaluation strategy. It uses the configured {@link Executor}
- * for the fitness evaluation.
- *
- * @param the gene type
- * @param the fitness result type
- *
- * @author Franz Wilhelmstötter
- * @version !__version__!
- * @since 4.2
- */
-public final class ExecutorEvaluator<
- G extends Gene, G>,
- C extends Comparable super C>
->
- extends AbstractEvaluator
-{
-
- private final Executor _executor;
-
- public ExecutorEvaluator(
- final Function super Genotype, ? extends C> function,
- final Executor executor
- ) {
- super(function);
- _executor = requireNonNull(executor);
- }
-
- public ExecutorEvaluator with(final Executor executor) {
- return new ExecutorEvaluator<>(_function, executor);
- }
-
- @Override
- protected void execute(final Seq extends Runnable> tasks) {
- try (var c = BatchExecutor.with(_executor)) {
- c.execute(tasks);
- }
- }
-
-}
diff --git a/jenetics/src/main/java/io/jenetics/internal/concurrent/FitnessEvaluator.java b/jenetics/src/main/java/io/jenetics/internal/concurrent/FitnessEvaluator.java
deleted file mode 100644
index 91711b27e3..0000000000
--- a/jenetics/src/main/java/io/jenetics/internal/concurrent/FitnessEvaluator.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Java Genetic Algorithm Library (@__identifier__@).
- * Copyright (c) @__year__@ Franz Wilhelmstötter
- *
- * 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.
- *
- * Author:
- * Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
- */
-package io.jenetics.internal.concurrent;
-
-import java.util.function.Function;
-
-import io.jenetics.Gene;
-import io.jenetics.Genotype;
-import io.jenetics.engine.Evaluator;
-
-/**
- * @param the gene type
- * @param the fitness result type
- *
- * @author Franz Wilhelmstötter
- * @version !__version__!
- * @since !__version__!
- */
-public interface FitnessEvaluator<
- G extends Gene, G>,
- C extends Comparable super C>
->
- extends Evaluator
-{
-
- Function super Genotype, ? extends C> function();
-
-}
diff --git a/jenetics/src/main/java/io/jenetics/internal/concurrent/Futures.java b/jenetics/src/main/java/io/jenetics/internal/concurrent/Futures.java
index bf71b315f0..2eec487a63 100644
--- a/jenetics/src/main/java/io/jenetics/internal/concurrent/Futures.java
+++ b/jenetics/src/main/java/io/jenetics/internal/concurrent/Futures.java
@@ -52,7 +52,8 @@ static void join(final Iterable extends Future>> futures) {
future.get();
}
future = null;
- } catch (InterruptedException | ExecutionException |
+ } catch (InterruptedException |
+ ExecutionException |
CancellationException e)
{
exception = e;
diff --git a/jenetics/src/main/java/io/jenetics/internal/concurrent/VirtualThreadEvaluator.java b/jenetics/src/main/java/io/jenetics/internal/concurrent/VirtualThreadEvaluator.java
deleted file mode 100644
index d64cee8958..0000000000
--- a/jenetics/src/main/java/io/jenetics/internal/concurrent/VirtualThreadEvaluator.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Java Genetic Algorithm Library (@__identifier__@).
- * Copyright (c) @__year__@ Franz Wilhelmstötter
- *
- * 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.
- *
- * Author:
- * Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
- */
-package io.jenetics.internal.concurrent;
-
-import java.util.concurrent.Executors;
-import java.util.function.Function;
-
-import io.jenetics.Gene;
-import io.jenetics.Genotype;
-import io.jenetics.util.Seq;
-
-/**
- * @param the gene type
- * @param the fitness result type
- *
- * @author Franz Wilhelmstötter
- * @version !__version__!
- * @since !__version__!
- */
-public final class VirtualThreadEvaluator<
- G extends Gene, G>,
- C extends Comparable super C>
->
- extends AbstractEvaluator
-{
-
- public VirtualThreadEvaluator(
- final Function super Genotype, ? extends C> function
- ) {
- super(function);
- }
-
- @Override
- protected void execute(final Seq extends Runnable> tasks) {
- try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
- tasks.forEach(executor::execute);
- }
- }
-}
diff --git a/jenetics/src/main/java/io/jenetics/util/BatchExecutor.java b/jenetics/src/main/java/io/jenetics/util/BatchExecutor.java
new file mode 100644
index 0000000000..d4b78bd3ae
--- /dev/null
+++ b/jenetics/src/main/java/io/jenetics/util/BatchExecutor.java
@@ -0,0 +1,85 @@
+/*
+ * Java Genetic Algorithm Library (@__identifier__@).
+ * Copyright (c) @__year__@ Franz Wilhelmstötter
+ *
+ * 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.
+ *
+ * Author:
+ * Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
+ */
+package io.jenetics.util;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ForkJoinPool;
+
+import io.jenetics.internal.concurrent.BatchExec;
+import io.jenetics.internal.concurrent.BatchForkJoinPool;
+
+/**
+ * Batch executor interface, which is used for evaluating a batch of
+ * runnables. The tasks of a batch are executed concurrently and the
+ * {@link #execute(Seq)} method will return, if all tasks of the batch have
+ * been executed.
+ *
+ * @author Franz Wilhelmstötter
+ * @version !__version__!
+ * @since !__version__!
+ */
+@FunctionalInterface
+public interface BatchExecutor {
+
+ /**
+ * Executes the runnables of the {@code batch} concurrently and returns,
+ * when all tasks have been executed.
+ *
+ * @param batch the sequence of runnable to be executed concurrently
+ * @throws NullPointerException if the given {@code batch} is {@code null}
+ */
+ void execute(final Seq extends Runnable> batch);
+
+ /**
+ * Create a batch executor, where the execution is forwarded to the given
+ * {@code executor}.
+ *
+ * @param executor the executor, which is actually executing the tasks
+ * @return a new batch executor
+ * @throws NullPointerException if the given {@code executor} is {@code null}
+ */
+ static BatchExecutor of(final Executor executor) {
+ requireNonNull(executor);
+
+ if (executor instanceof ForkJoinPool pool) {
+ return new BatchForkJoinPool(pool);
+ } else {
+ return new BatchExec(executor);
+ }
+ }
+
+ /**
+ * Return a batch executor, where each task of a given batch is
+ * executed in its own virtual thread.
+ *
+ * @return a new virtual thread batch executor object
+ */
+ static BatchExecutor ofVirtualThreads() {
+ return batch -> {
+ try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
+ batch.forEach(executor::execute);
+ }
+ };
+ }
+
+}
diff --git a/jenetics/src/main/java/module-info.java b/jenetics/src/main/java/module-info.java
index 939881b21e..5c65c24bec 100644
--- a/jenetics/src/main/java/module-info.java
+++ b/jenetics/src/main/java/module-info.java
@@ -32,5 +32,4 @@
exports io.jenetics.internal.engine to io.jenetics.ext;
exports io.jenetics.internal.math to io.jenetics.ext;
exports io.jenetics.internal.util to io.jenetics.ext, io.jenetics.prog;
- exports io.jenetics.internal.concurrent;
}
diff --git a/jenetics/src/test/java/io/jenetics/engine/EngineTest.java b/jenetics/src/test/java/io/jenetics/engine/EngineTest.java
index 0d60416fba..20020ec045 100644
--- a/jenetics/src/test/java/io/jenetics/engine/EngineTest.java
+++ b/jenetics/src/test/java/io/jenetics/engine/EngineTest.java
@@ -521,4 +521,8 @@ public void constantPopulationForZeroOffspring() {
.collect(EvolutionResult.toBestEvolutionResult());
}
+ @Test
+ public void foo() {
+ }
+
}
diff --git a/jenetics/src/test/java/io/jenetics/internal/concurrent/BatchExecutorTest.java b/jenetics/src/test/java/io/jenetics/internal/concurrent/BatchExecutorTest.java
index a1c695112f..c245d14ddb 100644
--- a/jenetics/src/test/java/io/jenetics/internal/concurrent/BatchExecutorTest.java
+++ b/jenetics/src/test/java/io/jenetics/internal/concurrent/BatchExecutorTest.java
@@ -42,9 +42,7 @@ public void cpuTime() {
.collect(ISeq.toISeq());
final long start = System.currentTimeMillis();
- try (var concurrency = BatchExecutor.with(ForkJoinPool.commonPool())) {
- concurrency.execute(runnables);
- }
+ new BatchExec(ForkJoinPool.commonPool()).execute(runnables);
final long stop = System.currentTimeMillis();
System.out.println("Runtime: " + (stop - start)/1000.0);
}
@@ -75,7 +73,7 @@ public void run() {
//@org.testng.annotations.Test
public void maxBatchSize() {
System.setProperty("io.jenetics.concurrency.maxBatchSize", "1000000");
- assertThat(BatchExecutor.maxBatchSize()).isEqualTo(1000000);
+ assertThat(BatchExec.maxBatchSize()).isEqualTo(1000000);
}
}
diff --git a/jenetics/src/test/java/io/jenetics/internal/concurrent/ExecutorEvaluatorTest.java b/jenetics/src/test/java/io/jenetics/internal/concurrent/ExecutorEvaluatorTest.java
index 31dbddaf3e..90f9eec1ab 100644
--- a/jenetics/src/test/java/io/jenetics/internal/concurrent/ExecutorEvaluatorTest.java
+++ b/jenetics/src/test/java/io/jenetics/internal/concurrent/ExecutorEvaluatorTest.java
@@ -27,6 +27,8 @@
import io.jenetics.Genotype;
import io.jenetics.Phenotype;
import io.jenetics.engine.Evaluator;
+import io.jenetics.engine.FitnessEvaluator;
+import io.jenetics.util.BatchExecutor;
import io.jenetics.util.ISeq;
/**
@@ -44,8 +46,12 @@ public void evaluateSerial() {
phenotypes.forEach(pt -> Assert.assertTrue(pt.nonEvaluated()));
- final Evaluator evaluator =
- new ExecutorEvaluator<>(gt -> gt.gene().doubleValue(), Runnable::run);
+ final Evaluator
+ evaluator =
+ new FitnessEvaluator<>(
+ gt -> gt.gene().doubleValue(),
+ BatchExecutor.of(Runnable::run)
+ );
final ISeq> evaluated = evaluator.eval(phenotypes);