Skip to content

Commit ba12350

Browse files
gselzerhinerm
authored andcommitted
Scijava-concurrent: initial commit
Note that scijava-concurrent is a fork of the imglib2-parallel library - see https://github.com/imglib/imglib2
1 parent b052d25 commit ba12350

16 files changed

Lines changed: 1874 additions & 0 deletions

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
<module>imagej/imagej2-legacy</module>
5353
<module>scijava/scijava-collections</module>
5454
<module>scijava/scijava-common3</module>
55+
<module>scijava/scijava-concurrent</module>
5556
<module>scijava/scijava-discovery</module>
5657
<module>scijava/scijava-discovery-therapi</module>
5758
<module>scijava/scijava-discovery-test</module>

scijava/scijava-concurrent/pom.xml

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
5+
<parent>
6+
<groupId>org.scijava</groupId>
7+
<artifactId>scijava-incubator</artifactId>
8+
<version>0-SNAPSHOT</version>
9+
<relativePath>../..</relativePath>
10+
</parent>
11+
12+
<artifactId>scijava-concurrent</artifactId>
13+
14+
<name>SciJava Concurrent</name>
15+
<description>SciJava library for general parallel processing support.</description>
16+
<url>https://github.com/scijava/scijava-concurrent</url>
17+
<inceptionYear>2021</inceptionYear>
18+
<organization>
19+
<name>SciJava</name>
20+
<url>https://scijava.org/</url>
21+
</organization>
22+
<licenses>
23+
<license>
24+
<name>Simplified BSD License</name>
25+
<distribution>repo</distribution>
26+
</license>
27+
</licenses>
28+
29+
<developers>
30+
<developer>
31+
<id>ctrueden</id>
32+
<name>Curtis Rueden</name>
33+
<url>https://imagej.net/User:Rueden</url>
34+
<roles>
35+
<role>founder</role>
36+
<role>lead</role>
37+
<role>reviewer</role>
38+
<role>support</role>
39+
<role>maintainer</role>
40+
</roles>
41+
</developer>
42+
<developer>
43+
<id>gselzer</id>
44+
<name>Gabriel Selzer</name>
45+
<roles>
46+
<role>founder</role>
47+
<role>developer</role>
48+
<role>debugger</role>
49+
<role>reviewer</role>
50+
<role>support</role>
51+
</roles>
52+
</developer>
53+
</developers>
54+
<contributors>
55+
<contributor>
56+
<name>Matthias Arzt</name>
57+
<url>https://imagej.net/people/maarzt</url>
58+
<roles><role>developer</role></roles>
59+
<properties><id>maarzt</id></properties>
60+
</contributor>
61+
</contributors>
62+
63+
<mailingLists>
64+
<mailingList>
65+
<name>Image.sc Forum</name>
66+
<archive>https://forum.image.sc/tags/scijava-concurrent</archive>
67+
</mailingList>
68+
</mailingLists>
69+
70+
<scm>
71+
<connection>scm:git:git://github.com/scijava/incubator</connection>
72+
<developerConnection>scm:git:git@github.com:scijava/incubator</developerConnection>
73+
<tag>HEAD</tag>
74+
<url>https://github.com/scijava/incubator</url>
75+
</scm>
76+
<issueManagement>
77+
<system>GitHub Issues</system>
78+
<url>https://github.com/scijava/scijava-concurrent/issues</url>
79+
</issueManagement>
80+
<ciManagement>
81+
<system>GitHub Actions</system>
82+
<url>https://github.com/scijava/incubator/actions</url>
83+
</ciManagement>
84+
85+
<properties>
86+
<package-name>org.scijava.concurrent</package-name>
87+
88+
<license.licenseName>bsd_2</license.licenseName>
89+
<license.copyrightOwners>SciJava developers.</license.copyrightOwners>
90+
</properties>
91+
92+
<build>
93+
<plugins>
94+
<plugin>
95+
<artifactId>maven-compiler-plugin</artifactId>
96+
<configuration>
97+
<annotationProcessorPaths>
98+
<path>
99+
<groupId>org.openjdk.jmh</groupId>
100+
<artifactId>jmh-generator-annprocess</artifactId>
101+
<version>${jmh-generator-annprocess.version}</version>
102+
</path>
103+
</annotationProcessorPaths>
104+
</configuration>
105+
</plugin>
106+
</plugins>
107+
</build>
108+
109+
<dependencies>
110+
<!-- SciJava dependencies -->
111+
112+
<!-- Third-party dependencies -->
113+
114+
<!-- Test scope dependencies -->
115+
<dependency>
116+
<groupId>org.junit.jupiter</groupId>
117+
<artifactId>junit-jupiter-api</artifactId>
118+
<scope>test</scope>
119+
</dependency>
120+
<dependency>
121+
<groupId>org.junit.jupiter</groupId>
122+
<artifactId>junit-jupiter-engine</artifactId>
123+
<scope>test</scope>
124+
</dependency>
125+
<dependency>
126+
<groupId>org.junit.vintage</groupId>
127+
<artifactId>junit-vintage-engine</artifactId>
128+
<scope>test</scope>
129+
</dependency>
130+
<dependency>
131+
<groupId>org.openjdk.jmh</groupId>
132+
<artifactId>jmh-core</artifactId>
133+
<scope>test</scope>
134+
</dependency>
135+
<dependency>
136+
<groupId>org.openjdk.jmh</groupId>
137+
<artifactId>jmh-generator-annprocess</artifactId>
138+
<scope>test</scope>
139+
</dependency>
140+
</dependencies>
141+
</project>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module org.scijava.concurrent {
2+
3+
exports org.scijava.concurrent;
4+
5+
opens org.scijava.concurrent to org.scijava;
6+
7+
}
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
/*
2+
* #%L
3+
* ImgLib2: a general-purpose, multidimensional image processing library.
4+
* %%
5+
* Copyright (C) 2009 - 2021 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld,
6+
* John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke,
7+
* Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner,
8+
* Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert,
9+
* Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin,
10+
* Jean-Yves Tinevez and Michael Zinsmaier.
11+
* %%
12+
* Redistribution and use in source and binary forms, with or without
13+
* modification, are permitted provided that the following conditions are met:
14+
*
15+
* 1. Redistributions of source code must retain the above copyright notice,
16+
* this list of conditions and the following disclaimer.
17+
* 2. Redistributions in binary form must reproduce the above copyright notice,
18+
* this list of conditions and the following disclaimer in the documentation
19+
* and/or other materials provided with the distribution.
20+
*
21+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
25+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31+
* POSSIBILITY OF SUCH DAMAGE.
32+
* #L%
33+
*/
34+
package org.scijava.concurrent;
35+
36+
import java.lang.reflect.Array;
37+
import java.util.ArrayList;
38+
import java.util.List;
39+
import java.util.concurrent.Callable;
40+
import java.util.concurrent.ExecutionException;
41+
import java.util.concurrent.ExecutorService;
42+
import java.util.concurrent.Executors;
43+
import java.util.concurrent.ForkJoinPool;
44+
import java.util.concurrent.Future;
45+
import java.util.concurrent.ThreadPoolExecutor;
46+
import java.util.function.Consumer;
47+
import java.util.function.Function;
48+
49+
/**
50+
* A {@link TaskExecutor} that wraps around a given {@link ExecutorService}.
51+
*/
52+
public class DefaultTaskExecutor implements TaskExecutor
53+
{
54+
55+
private final ExecutorService executorService;
56+
57+
public DefaultTaskExecutor( final ExecutorService executorService )
58+
{
59+
this.executorService = executorService;
60+
}
61+
62+
@Override
63+
public ExecutorService getExecutorService()
64+
{
65+
return executorService;
66+
}
67+
68+
@Override
69+
public int getParallelism()
70+
{
71+
if ( executorService instanceof ForkJoinPool )
72+
return ( ( ForkJoinPool ) executorService ).getParallelism();
73+
else if ( executorService instanceof ThreadPoolExecutor )
74+
return Math.max( 1, ( ( ThreadPoolExecutor ) executorService ).getCorePoolSize() );
75+
else if ( executorService instanceof ForkJoinExecutorService )
76+
return ( ( ForkJoinExecutorService ) executorService ).getParallelism();
77+
else if ( executorService instanceof SequentialExecutorService )
78+
return ( ( SequentialExecutorService ) executorService ).getParallelism();
79+
return Runtime.getRuntime().availableProcessors();
80+
}
81+
82+
@Override
83+
public void runAll( final List< Runnable > tasks )
84+
{
85+
final List< Callable< Object > > callables = new ArrayList<>( tasks.size() );
86+
// use for-loop because stream with collect(Collectors.toList) is slow.
87+
for ( Runnable task : tasks )
88+
callables.add( Executors.callable( task ) );
89+
invokeAllIgnoreResults( callables );
90+
}
91+
92+
@Override
93+
public int suggestNumberOfTasks()
94+
{
95+
int parallelism = getParallelism();
96+
return ( parallelism == 1 ) ? 1 : ( int ) Math.min( ( long ) parallelism * 4L, ( long ) Integer.MAX_VALUE );
97+
}
98+
99+
@Override
100+
public < T > void forEach( final List< ? extends T > parameters, final Consumer< ? super T > task )
101+
{
102+
final List< Callable< Object > > callables = new ArrayList<>( parameters.size() );
103+
// use for-loop because stream with collect(Collectors.toList) is slow.
104+
for ( T parameter : parameters )
105+
callables.add( () -> {
106+
task.accept( parameter );
107+
return null;
108+
} );
109+
invokeAllIgnoreResults( callables );
110+
}
111+
112+
@Override
113+
public < T, R > List< R > forEachApply( List< ? extends T > parameters, Function< ? super T, ? extends R > task )
114+
{
115+
final List< Callable< R > > callables = new ArrayList<>( parameters.size() );
116+
// use for-loop because stream with collect(Collectors.toList) is slow.
117+
for ( T parameter : parameters )
118+
callables.add( () -> task.apply( parameter ) );
119+
try
120+
{
121+
final List< Future< R > > futures = executorService.invokeAll( callables );
122+
final List< R > results = new ArrayList<>( futures.size() );
123+
for ( Future< R > future : futures )
124+
results.add( future.get() );
125+
return results;
126+
}
127+
catch ( InterruptedException | ExecutionException e )
128+
{
129+
throw unwrapExecutionException( e );
130+
}
131+
}
132+
133+
private void invokeAllIgnoreResults( final List< Callable< Object > > callables )
134+
{
135+
try
136+
{
137+
final List< Future< Object > > futures = executorService.invokeAll( callables );
138+
for ( Future< Object > future : futures )
139+
future.get();
140+
}
141+
catch ( InterruptedException | ExecutionException e )
142+
{
143+
throw unwrapExecutionException( e );
144+
}
145+
}
146+
147+
/**
148+
* {@link ExecutorService} wrap all exceptions thrown by any task into a
149+
* {@link ExecutionException}, this makes the stack traces rather hard to
150+
* read. This method unwraps the {@link ExecutionException} and thereby
151+
* reveals the original exception, and ensures it's complete stack trace.
152+
*/
153+
private RuntimeException unwrapExecutionException( Throwable e )
154+
{
155+
if ( e instanceof ExecutionException )
156+
{
157+
final Throwable cause = e.getCause();
158+
cause.setStackTrace( concatenate( cause.getStackTrace(), e.getStackTrace() ) );
159+
e = cause;
160+
}
161+
if ( e instanceof RuntimeException )
162+
throw ( RuntimeException ) e;
163+
else
164+
return new RuntimeException( e );
165+
}
166+
167+
private < T > T[] concatenate( final T[] a, final T[] b )
168+
{
169+
int aLen = a.length;
170+
int bLen = b.length;
171+
@SuppressWarnings( "unchecked" )
172+
T[] c = ( T[] ) Array.newInstance( a.getClass().getComponentType(), aLen + bLen );
173+
System.arraycopy( a, 0, c, 0, aLen );
174+
System.arraycopy( b, 0, c, aLen, bLen );
175+
return c;
176+
}
177+
178+
@Override
179+
public void close()
180+
{
181+
executorService.shutdown();
182+
}
183+
}

0 commit comments

Comments
 (0)