From cef19e79095720eb39ad6ce4429a63263a4f801c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franz=20Wilhelmst=C3=B6tter?= Date: Mon, 7 Aug 2023 23:12:38 +0200 Subject: [PATCH] #878: Refactoring of virtual thread executor. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Franz Wilhelmstötter --- build.gradle.kts | 3 +- buildSrc/resources/javadoc/stylesheet.css | 881 ------------------ .../main/java/io/jenetics/engine/Engine.java | 72 +- .../java/io/jenetics/engine/Evaluators.java | 194 +--- .../FitnessEvaluator.java} | 26 +- .../{BatchExecutor.java => BatchExec.java} | 41 +- .../concurrent/BatchForkJoinPool.java | 11 +- .../concurrent/ExecutorEvaluator.java | 70 -- .../internal/concurrent/FitnessEvaluator.java | 45 - .../jenetics/internal/concurrent/Futures.java | 3 +- .../concurrent/VirtualThreadEvaluator.java | 56 -- .../java/io/jenetics/util/BatchExecutor.java | 85 ++ jenetics/src/main/java/module-info.java | 1 - .../java/io/jenetics/engine/EngineTest.java | 4 + .../concurrent/BatchExecutorTest.java | 6 +- .../concurrent/ExecutorEvaluatorTest.java | 10 +- 16 files changed, 203 insertions(+), 1305 deletions(-) delete mode 100644 buildSrc/resources/javadoc/stylesheet.css rename jenetics/src/main/java/io/jenetics/{internal/concurrent/AbstractEvaluator.java => engine/FitnessEvaluator.java} (78%) rename jenetics/src/main/java/io/jenetics/internal/concurrent/{BatchExecutor.java => BatchExec.java} (85%) delete mode 100644 jenetics/src/main/java/io/jenetics/internal/concurrent/ExecutorEvaluator.java delete mode 100644 jenetics/src/main/java/io/jenetics/internal/concurrent/FitnessEvaluator.java delete mode 100644 jenetics/src/main/java/io/jenetics/internal/concurrent/VirtualThreadEvaluator.java create mode 100644 jenetics/src/main/java/io/jenetics/util/BatchExecutor.java diff --git a/build.gradle.kts b/build.gradle.kts index dc32380251..344477ba1c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -179,7 +179,6 @@ fun setupJavadoc(project: Project, taskName: String) { doclet.windowTitle = "Jenetics ${project.version}" doclet.docTitle = "

Jenetics ${project.version}

" doclet.bottom = "© ${Env.COPYRIGHT_YEAR} Franz Wilhelmstötter  (${Env.BUILD_DATE})" - doclet.stylesheetFile = project.file("${project.rootDir}/buildSrc/resources/javadoc/stylesheet.css") doclet.addStringOption("noqualifier", "io.jenetics.internal.collection") doclet.tags = listOf( @@ -226,10 +225,12 @@ fun setupJavadoc(project: Project, taskName: String) { } javadoc.doLast { + /* val colorizer = project.tasks.findByName("${taskName}colorizer") colorizer?.actions?.forEach { it.execute(colorizer) } + */ val java2html = project.tasks.findByName("${taskName}java2html") java2html?.actions?.forEach { diff --git a/buildSrc/resources/javadoc/stylesheet.css b/buildSrc/resources/javadoc/stylesheet.css deleted file mode 100644 index d14736d065..0000000000 --- a/buildSrc/resources/javadoc/stylesheet.css +++ /dev/null @@ -1,881 +0,0 @@ -/* - * Javadoc style sheet - */ - -@import url('resources/fonts/dejavu.css'); - -/* - * Styles for individual HTML elements. - * - * These are styles that are specific to individual HTML elements. Changing them affects the style of a particular - * HTML element throughout the page. - */ - -div.code { - background-color:#F9F9F9; - margin-top:8px; - margin-bottom:8px; - margin-left:8px; - margin-right:25px; - border:1px solid #9EADC0; -} - -code[lang="java"] { - white-space:pre; - margin-top:5px; - font-family:'DejaVu Sans Mono', monospace; - font-size:1.0em; -} - -body { - background-color:#F5F5F5; - color:#353833; - font-family:'DejaVu Sans', Arial, Helvetica, sans-serif; - font-size:14px; - margin:0; - padding:0; - height:100%; - width:100%; -} -iframe { - margin:0; - padding:0; - height:100%; - width:100%; - overflow-y:scroll; - border:none; -} -a:link, a:visited { - text-decoration:none; - color:#4A6782; -} -a[href]:hover, a[href]:focus { - text-decoration:none; - color:#bb7a2a; -} -a[name] { - color:#353833; -} -pre { - font-family:'DejaVu Sans Mono', monospace; - font-size:14px; -} -h1 { - font-size:20px; -} -h2 { - font-size:18px; -} -h3 { - font-size:16px; -} -h4 { - font-size:15px; -} -h5 { - font-size:14px; -} -h6 { - font-size:13px; -} -ul { - list-style-type:disc; -} -code, tt { - font-family:'DejaVu Sans Mono', monospace; -} -:not(h1, h2, h3, h4, h5, h6) > code, -:not(h1, h2, h3, h4, h5, h6) > tt { - font-size:14px; - padding-top:4px; - margin-top:8px; - line-height:1.4em; -} -dt code { - font-family:'DejaVu Sans Mono', monospace; - font-size:14px; - padding-top:4px; -} -.summary-table dt code { - font-family:'DejaVu Sans Mono', monospace; - font-size:14px; - vertical-align:top; - padding-top:4px; -} -sup { - font-size:8px; -} -button { - font-family: 'DejaVu Sans', Arial, Helvetica, sans-serif; - font-size: 14px; -} -/* - * Styles for HTML generated by javadoc. - * - * These are style classes that are used by the standard doclet to generate HTML documentation. - */ - -/* - * Styles for document title and copyright. - */ -.clear { - clear:both; - height:0; - overflow:hidden; -} -.about-language { - float:right; - padding:0 21px 8px 8px; - font-size:11px; - margin-top:-9px; - height:2.9em; -} -.legal-copy { - margin-left:.5em; -} -.tab { - background-color:#0066FF; - color:#ffffff; - padding:8px; - width:5em; - font-weight:bold; -} -/* - * Styles for navigation bar. - */ -@media screen { - .flex-box { - position:fixed; - display:flex; - flex-direction:column; - height: 100%; - width: 100%; - } - .flex-header { - flex: 0 0 auto; - } - .flex-content { - flex: 1 1 auto; - overflow-y: auto; - } -} -.top-nav { - background-color:#4D7A97; - color:#FFFFFF; - float:left; - padding:0; - width:100%; - clear:right; - min-height:2.8em; - padding-top:10px; - overflow:hidden; - font-size:12px; -} -.sub-nav { - background-color:#dee3e9; - float:left; - width:100%; - overflow:hidden; - font-size:12px; -} -.sub-nav div { - clear:left; - float:left; - padding:0 0 5px 6px; - text-transform:uppercase; -} -.sub-nav .nav-list { - padding-top:5px; -} -ul.nav-list { - display:block; - margin:0 25px 0 0; - padding:0; -} -ul.sub-nav-list { - float:left; - margin:0 25px 0 0; - padding:0; -} -ul.nav-list li { - list-style:none; - float:left; - padding: 5px 6px; - text-transform:uppercase; -} -.sub-nav .nav-list-search { - float:right; - margin:0 0 0 0; - padding:5px 6px; - clear:none; -} -.nav-list-search label { - position:relative; - right:-16px; -} -ul.sub-nav-list li { - list-style:none; - float:left; - padding-top:10px; -} -.top-nav a:link, .top-nav a:active, .top-nav a:visited { - color:#FFFFFF; - text-decoration:none; - text-transform:uppercase; -} -.top-nav a:hover { - text-decoration:none; - color:#bb7a2a; - text-transform:uppercase; -} -.nav-bar-cell1-rev { - background-color:#F8981D; - color:#253441; - margin: auto 5px; -} -.skip-nav { - position:absolute; - top:auto; - left:-9999px; - overflow:hidden; -} -/* - * Hide navigation links and search box in print layout - */ -@media print { - ul.nav-list, div.sub-nav { - display:none; - } -} -/* - * Styles for page header and footer. - */ -.title { - color:#2c4557; - margin:10px 0; -} -.sub-title { - margin:5px 0 0 0; -} -.header ul { - margin:0 0 15px 0; - padding:0; -} -.header ul li, .footer ul li { - list-style:none; - font-size:13px; -} -/* - * Styles for headings. - */ -body.class-declaration-page .summary h2, -body.class-declaration-page .details h2, -body.class-use-page h2, -body.module-declaration-page .block-list h2 { - font-style: italic; - padding:0; - margin:15px 0; -} -body.class-declaration-page .summary h3, -body.class-declaration-page .details h3, -body.class-declaration-page .summary .inherited-list h2 { - background-color:#dee3e9; - border:1px solid #d0d9e0; - margin:0 0 6px -8px; - padding:7px 5px; -} -/* - * Styles for page layout containers. - */ -main { - clear:both; - padding:10px 20px; - position:relative; -} -dl.notes > dt { - font-family: 'DejaVu Sans', Arial, Helvetica, sans-serif; - font-size:12px; - font-weight:bold; - margin:10px 0 0 0; - color:#4E4E4E; -} -dl.notes > dd { - margin:5px 10px 10px 0; - font-size:14px; - font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif; -} -dl.name-value > dt { - margin-left:1px; - font-size:1.1em; - display:inline; - font-weight:bold; -} -dl.name-value > dd { - margin:0 0 0 1px; - font-size:1.1em; - display:inline; -} -/* - * Styles for lists. - */ -li.circle { - list-style:circle; -} -ul.horizontal li { - display:inline; - font-size:0.9em; -} -div.inheritance { - margin:0; - padding:0; -} -div.inheritance div.inheritance { - margin-left:2em; -} -ul.block-list, -ul.details-list, -ul.member-list, -ul.summary-list { - margin:10px 0 10px 0; - padding:0; -} -ul.block-list > li, -ul.details-list > li, -ul.member-list > li, -ul.summary-list > li { - list-style:none; - margin-bottom:15px; - line-height:1.4; -} -.summary-table dl, .summary-table dl dt, .summary-table dl dd { - margin-top:0; - margin-bottom:1px; -} -ul.see-list, ul.see-list-long { - padding-left: 0; - list-style: none; -} -ul.see-list li { - display: inline; -} -ul.see-list li:not(:last-child):after, -ul.see-list-long li:not(:last-child):after { - content: ", "; - white-space: pre-wrap; -} -/* - * Styles for tables. - */ -.summary-table, .details-table { - width:100%; - border-spacing:0; - border-left:1px solid #EEE; - border-right:1px solid #EEE; - border-bottom:1px solid #EEE; - padding:0; -} -.caption { - position:relative; - text-align:left; - background-repeat:no-repeat; - color:#253441; - font-weight:bold; - clear:none; - overflow:hidden; - padding:0; - padding-top:10px; - padding-left:1px; - margin:0; - white-space:pre; -} -.caption a:link, .caption a:visited { - color:#1f389c; -} -.caption a:hover, -.caption a:active { - color:#FFFFFF; -} -.caption span { - white-space:nowrap; - padding-top:5px; - padding-left:12px; - padding-right:12px; - padding-bottom:7px; - display:inline-block; - float:left; - background-color:#F8981D; - border: none; - height:16px; -} -div.table-tabs { - padding:10px 0 0 1px; - margin:0; -} -div.table-tabs > button { - border: none; - cursor: pointer; - padding: 5px 12px 7px 12px; - font-weight: bold; - margin-right: 3px; -} -div.table-tabs > button.active-table-tab { - background: #F8981D; - color: #253441; -} -div.table-tabs > button.table-tab { - background: #4D7A97; - color: #FFFFFF; -} -.two-column-summary { - display: grid; - grid-template-columns: minmax(15%, max-content) minmax(15%, auto); -} -.three-column-summary { - display: grid; - grid-template-columns: minmax(10%, max-content) minmax(15%, max-content) minmax(15%, auto); -} -.four-column-summary { - display: grid; - grid-template-columns: minmax(10%, max-content) minmax(10%, max-content) minmax(10%, max-content) minmax(10%, auto); -} -@media screen and (max-width: 600px) { - .two-column-summary { - display: grid; - grid-template-columns: 1fr; - } -} -@media screen and (max-width: 800px) { - .three-column-summary { - display: grid; - grid-template-columns: minmax(10%, max-content) minmax(25%, auto); - } - .three-column-summary .col-last { - grid-column-end: span 2; - } -} -@media screen and (max-width: 1000px) { - .four-column-summary { - display: grid; - grid-template-columns: minmax(15%, max-content) minmax(15%, auto); - } -} -.summary-table > div, .details-table > div { - text-align:left; - padding: 8px 3px 3px 7px; -} -.col-first, .col-second, .col-last, .col-constructor-name, .col-summary-item-name { - vertical-align:top; - padding-right:0; - padding-top:8px; - padding-bottom:3px; -} -.table-header { - background:#dee3e9; - font-weight: bold; -} -.col-first, .col-first { - font-size:13px; -} -.col-second, .col-second, .col-last, .col-constructor-name, .col-summary-item-name, .col-last { - font-size:13px; -} -.col-first, .col-second, .col-constructor-name { - vertical-align:top; - overflow: auto; -} -.col-last { - white-space:normal; -} -.col-first a:link, .col-first a:visited, -.col-second a:link, .col-second a:visited, -.col-first a:link, .col-first a:visited, -.col-second a:link, .col-second a:visited, -.col-constructor-name a:link, .col-constructor-name a:visited, -.col-summary-item-name a:link, .col-summary-item-name a:visited, -.constant-values-container a:link, .constant-values-container a:visited, -.all-classes-container a:link, .all-classes-container a:visited, -.all-packages-container a:link, .all-packages-container a:visited { - font-weight:bold; -} -.table-sub-heading-color { - background-color:#EEEEFF; -} -.even-row-color, .even-row-color .table-header { - background-color:#FFFFFF; -} -.odd-row-color, .odd-row-color .table-header { - background-color:#EEEEEF; -} -/* - * Styles for contents. - */ -.deprecated-content { - margin:0; - padding:10px 0; -} -div.block { - font-size:14px; - font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif; -} -.col-last div { - padding-top:0; -} -.col-last a { - padding-bottom:3px; -} -.module-signature, -.package-signature, -.type-signature, -.member-signature { - font-family:'DejaVu Sans Mono', monospace; - font-size:14px; - margin:14px 0; - white-space: pre-wrap; -} -.module-signature, -.package-signature, -.type-signature { - margin-top: 0; -} -.member-signature .type-parameters-long, -.member-signature .parameters, -.member-signature .exceptions { - display: inline-block; - vertical-align: top; - white-space: pre; -} -.member-signature .type-parameters { - white-space: normal; -} -/* - * Styles for formatting effect. - */ -.source-line-no { - color:green; - padding:0 30px 0 0; -} -h1.hidden { - visibility:hidden; - overflow:hidden; - font-size:10px; -} -.block { - display:block; - margin:0 10px 5px 0; - color:#474747; -} -.deprecated-label, .descfrm-type-label, .implementation-label, .member-name-label, .member-name-link, -.module-label-in-package, .module-label-in-type, .override-specify-label, .package-label-in-type, -.package-hierarchy-label, .type-name-label, .type-name-link, .search-tag-link, .preview-label { - font-weight:bold; -} -.deprecation-comment, .help-footnote, .preview-comment { - font-style:italic; -} -.deprecation-block { - font-size:14px; - font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif; - border-style:solid; - border-width:thin; - border-radius:10px; - padding:10px; - margin-bottom:10px; - margin-right:10px; - display:inline-block; -} -.preview-block { - font-size:14px; - font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif; - border-style:solid; - border-width:thin; - border-radius:10px; - padding:10px; - margin-bottom:10px; - margin-right:10px; - display:inline-block; -} -div.block div.deprecation-comment { - font-style:normal; -} -/* - * Styles specific to HTML5 elements. - */ -main, nav, header, footer, section { - display:block; -} -/* - * Styles for javadoc search. - */ -.ui-autocomplete-category { - font-weight:bold; - font-size:15px; - padding:7px 0 7px 3px; - background-color:#4D7A97; - color:#FFFFFF; -} -.result-item { - font-size:13px; -} -.ui-autocomplete { - max-height:85%; - max-width:65%; - overflow-y:scroll; - overflow-x:scroll; - white-space:nowrap; - box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23); -} -ul.ui-autocomplete { - position:fixed; - z-index:999999; -} -ul.ui-autocomplete li { - float:left; - clear:both; - width:100%; -} -.result-highlight { - font-weight:bold; -} -#search-input { - background-image:url('resources/glass.png'); - background-size:13px; - background-repeat:no-repeat; - background-position:2px 3px; - padding-left:20px; - position:relative; - right:-18px; - width:400px; -} -#reset-button { - background-color: rgb(255,255,255); - background-image:url('resources/x.png'); - background-position:center; - background-repeat:no-repeat; - background-size:12px; - border:0 none; - width:16px; - height:16px; - position:relative; - left:-4px; - top:-4px; - font-size:0px; -} -.watermark { - color:#545454; -} -.search-tag-desc-result { - font-style:italic; - font-size:11px; -} -.search-tag-holder-result { - font-style:italic; - font-size:12px; -} -.search-tag-result:target { - background-color:yellow; -} -.module-graph span { - display:none; - position:absolute; -} -.module-graph:hover span { - display:block; - margin: -100px 0 0 100px; - z-index: 1; -} -.inherited-list { - margin: 10px 0 10px 0; -} -section.class-description { - line-height: 1.4; -} -.summary section[class$="-summary"], .details section[class$="-details"], -.class-uses .detail, .serialized-class-details { - padding: 0px 20px 5px 10px; - border: 1px solid #ededed; - background-color: #f8f8f8; -} -.inherited-list, section[class$="-details"] .detail { - padding:0 0 5px 8px; - background-color:#ffffff; - border:none; -} -.vertical-separator { - padding: 0 5px; -} -ul.help-section-list { - margin: 0; -} -ul.help-subtoc > li { - display: inline-block; - padding-right: 5px; - font-size: smaller; -} -ul.help-subtoc > li::before { - content: "\2022" ; - padding-right:2px; -} -span.help-note { - font-style: italic; -} -/* - * Indicator icon for external links. - */ -main a[href*="://"]::after { - content:""; - display:inline-block; - background-image:url('data:image/svg+xml; utf8, \ - \ - \ - '); - background-size:100% 100%; - width:7px; - height:7px; - margin-left:2px; - margin-bottom:4px; -} -main a[href*="://"]:hover::after, -main a[href*="://"]:focus::after { - background-image:url('data:image/svg+xml; utf8, \ - \ - \ - '); -} - -/* - * Styles for user-provided tables. - * - * borderless: - * No borders, vertical margins, styled caption. - * This style is provided for use with existing doc comments. - * In general, borderless tables should not be used for layout purposes. - * - * plain: - * Plain borders around table and cells, vertical margins, styled caption. - * Best for small tables or for complex tables for tables with cells that span - * rows and columns, when the "striped" style does not work well. - * - * striped: - * Borders around the table and vertical borders between cells, striped rows, - * vertical margins, styled caption. - * Best for tables that have a header row, and a body containing a series of simple rows. - */ - -table.borderless, -table.plain, -table.striped { - margin-top: 10px; - margin-bottom: 10px; -} -table.borderless > caption, -table.plain > caption, -table.striped > caption { - font-weight: bold; - font-size: smaller; -} -table.borderless th, table.borderless td, -table.plain th, table.plain td, -table.striped th, table.striped td { - padding: 2px 5px; -} -table.borderless, -table.borderless > thead > tr > th, table.borderless > tbody > tr > th, table.borderless > tr > th, -table.borderless > thead > tr > td, table.borderless > tbody > tr > td, table.borderless > tr > td { - border: none; -} -table.borderless > thead > tr, table.borderless > tbody > tr, table.borderless > tr { - background-color: transparent; -} -table.plain { - border-collapse: collapse; - border: 1px solid black; -} -table.plain > thead > tr, table.plain > tbody tr, table.plain > tr { - background-color: transparent; -} -table.plain > thead > tr > th, table.plain > tbody > tr > th, table.plain > tr > th, -table.plain > thead > tr > td, table.plain > tbody > tr > td, table.plain > tr > td { - border: 1px solid black; -} -table.striped { - border-collapse: collapse; - border: 1px solid black; -} -table.striped > thead { - background-color: #E3E3E3; -} -table.striped > thead > tr > th, table.striped > thead > tr > td { - border: 1px solid black; -} -table.striped > tbody > tr:nth-child(even) { - background-color: #EEE -} -table.striped > tbody > tr:nth-child(odd) { - background-color: #FFF -} -table.striped > tbody > tr > th, table.striped > tbody > tr > td { - border-left: 1px solid black; - border-right: 1px solid black; -} -table.striped > tbody > tr > th { - font-weight: normal; -} -/** - * Tweak font sizes and paddings for small screens. - */ -@media screen and (max-width: 1050px) { - #search-input { - width: 300px; - } -} -@media screen and (max-width: 800px) { - #search-input { - width: 200px; - } - .top-nav, - .bottom-nav { - font-size: 11px; - padding-top: 6px; - } - .sub-nav { - font-size: 11px; - } - .about-language { - padding-right: 16px; - } - ul.nav-list li, - .sub-nav .nav-list-search { - padding: 6px; - } - ul.sub-nav-list li { - padding-top: 5px; - } - main { - padding: 10px; - } - .summary section[class$="-summary"], .details section[class$="-details"], - .class-uses .detail, .serialized-class-details { - padding: 0 8px 5px 8px; - } - body { - -webkit-text-size-adjust: none; - } -} -@media screen and (max-width: 500px) { - #search-input { - width: 150px; - } - .top-nav, - .bottom-nav { - font-size: 10px; - } - .sub-nav { - font-size: 10px; - } - .about-language { - font-size: 10px; - padding-right: 12px; - } -} diff --git a/jenetics/src/main/java/io/jenetics/engine/Engine.java b/jenetics/src/main/java/io/jenetics/engine/Engine.java index c56ad01722..35c89bf6e4 100644 --- a/jenetics/src/main/java/io/jenetics/engine/Engine.java +++ b/jenetics/src/main/java/io/jenetics/engine/Engine.java @@ -27,6 +27,7 @@ import java.time.InstantSource; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +import java.util.concurrent.ForkJoinPool; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Stream; @@ -39,7 +40,7 @@ import io.jenetics.Optimize; import io.jenetics.Phenotype; import io.jenetics.Selector; -import io.jenetics.internal.concurrent.ExecutorEvaluator; +import io.jenetics.util.BatchExecutor; import io.jenetics.util.Copyable; import io.jenetics.util.Factory; import io.jenetics.util.ISeq; @@ -90,6 +91,23 @@ * performed by the {@link EvolutionStream}, which is created by the * {@code Engine}. * + *

Concurrency

+ * 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, ? 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> - Evaluator - serial(final Function, ? 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> - Evaluator serial( - final Function fitness, - final Function, ? 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> - Evaluator serial( - final Function 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> - Evaluator - ofVirtualThread(final Function, ? 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> - Evaluator ofVirtualThread( - final Function 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> - Evaluator ofVirtualThread( - final Function fitness, - final Function, ? 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> - Evaluator concurrent( - final Function, ? 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> - Evaluator concurrent( - final Function fitness, - final Function, ? 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> - Evaluator concurrent( - final Function 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, C extends Comparable > - implements FitnessEvaluator + implements Evaluator { - protected final Function, ? extends C> _function; + private final Function, ? extends C> _function; + private final BatchExecutor _executor; - protected AbstractEvaluator( - final Function, ? extends C> function + public FitnessEvaluator( + final Function, ? extends C> function, + final BatchExecutor executor ) { _function = requireNonNull(function); + _executor = requireNonNull(executor); } - @Override public Function, ? 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 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 batch) { if (batch.nonEmpty()) { final int[] parts = partition( @@ -59,41 +59,28 @@ public void execute(final Seq 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 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, - C extends Comparable -> - extends AbstractEvaluator -{ - - private final Executor _executor; - - public ExecutorEvaluator( - final Function, ? 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 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, - C extends Comparable -> - extends Evaluator -{ - - Function, ? 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> 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, - C extends Comparable -> - extends AbstractEvaluator -{ - - public VirtualThreadEvaluator( - final Function, ? extends C> function - ) { - super(function); - } - - @Override - protected void execute(final Seq 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 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);