From 0cd4d0e9cfef903d5a26af7d7d9fc140a454811a Mon Sep 17 00:00:00 2001 From: Matthias Arzt Date: Fri, 5 Nov 2021 13:31:20 +0100 Subject: [PATCH 1/3] Use LoopBuilder and Parallelization classes in Gauss3 This simplifies the code, but also improves the performance, because Gauss3.gauss(sigma, source, target) will no longer create it's own ExecutorService. This also means that the multi threading behaviour of Gauss3 can now conviniently be controled using the Parallelization class. For example: Parallelization.runSingleThreaded(() -> { Gauss3.gauss(sigma, source, target); }); --- .../AbstractMultiThreadedConvolution.java | 2 + .../algorithm/convolution/Concatenation.java | 6 +- .../algorithm/convolution/Convolution.java | 1 + .../convolution/LineConvolution.java | 132 +++++------------- .../MultiDimensionConvolution.java | 1 + .../net/imglib2/algorithm/gauss3/Gauss3.java | 15 +- .../convolution/ConcatenationTest.java | 7 +- .../convolution/LineConvolutionTest.java | 9 +- 8 files changed, 61 insertions(+), 112 deletions(-) diff --git a/src/main/java/net/imglib2/algorithm/convolution/AbstractMultiThreadedConvolution.java b/src/main/java/net/imglib2/algorithm/convolution/AbstractMultiThreadedConvolution.java index ff7624189..c9bf4e246 100644 --- a/src/main/java/net/imglib2/algorithm/convolution/AbstractMultiThreadedConvolution.java +++ b/src/main/java/net/imglib2/algorithm/convolution/AbstractMultiThreadedConvolution.java @@ -51,6 +51,7 @@ * * @author Matthias Arzt */ +@Deprecated public abstract class AbstractMultiThreadedConvolution< T > implements Convolution< T > { @@ -61,6 +62,7 @@ abstract protected void process( RandomAccessible< ? extends T > source, ExecutorService executorService, int numThreads ); + @Deprecated @Override public void setExecutor( final ExecutorService executor ) { diff --git a/src/main/java/net/imglib2/algorithm/convolution/Concatenation.java b/src/main/java/net/imglib2/algorithm/convolution/Concatenation.java index 589476490..b897a5341 100644 --- a/src/main/java/net/imglib2/algorithm/convolution/Concatenation.java +++ b/src/main/java/net/imglib2/algorithm/convolution/Concatenation.java @@ -64,10 +64,12 @@ class Concatenation< T > implements Convolution< T > this.steps = new ArrayList<>( steps ); } + @Deprecated @Override - public void setExecutor( final ExecutorService executor ) + public void setExecutor( ExecutorService executor ) { - steps.forEach( step -> step.setExecutor( executor ) ); + for ( Convolution step : steps ) + step.setExecutor( executor ); } @Override diff --git a/src/main/java/net/imglib2/algorithm/convolution/Convolution.java b/src/main/java/net/imglib2/algorithm/convolution/Convolution.java index e5b980f53..b3b1296fe 100644 --- a/src/main/java/net/imglib2/algorithm/convolution/Convolution.java +++ b/src/main/java/net/imglib2/algorithm/convolution/Convolution.java @@ -67,6 +67,7 @@ public interface Convolution< T > /** * Set the {@link ExecutorService} to be used for convolution. */ + @Deprecated default void setExecutor( final ExecutorService executor ) {} diff --git a/src/main/java/net/imglib2/algorithm/convolution/LineConvolution.java b/src/main/java/net/imglib2/algorithm/convolution/LineConvolution.java index 9aca7da82..6666a0228 100644 --- a/src/main/java/net/imglib2/algorithm/convolution/LineConvolution.java +++ b/src/main/java/net/imglib2/algorithm/convolution/LineConvolution.java @@ -33,44 +33,50 @@ */ package net.imglib2.algorithm.convolution; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; -import java.util.function.Consumer; -import java.util.function.Supplier; - import net.imglib2.FinalInterval; import net.imglib2.Interval; import net.imglib2.Localizable; -import net.imglib2.Point; import net.imglib2.RandomAccess; import net.imglib2.RandomAccessible; import net.imglib2.RandomAccessibleInterval; -import net.imglib2.util.IntervalIndexer; +import net.imglib2.loops.LoopBuilder; +import net.imglib2.parallel.Parallelization; +import net.imglib2.parallel.TaskExecutor; +import net.imglib2.parallel.TaskExecutors; +import net.imglib2.util.Cast; import net.imglib2.util.Intervals; +import net.imglib2.util.Localizables; import net.imglib2.view.Views; +import java.util.concurrent.ExecutorService; + /** * This class can be used to implement a separable convolution. It applies a * {@link LineConvolverFactory} on the given images. * * @author Matthias Arzt */ -public class LineConvolution< T > extends AbstractMultiThreadedConvolution< T > +public class LineConvolution< T > implements Convolution { private final LineConvolverFactory< ? super T > factory; private final int direction; + private ExecutorService executor; + public LineConvolution( final LineConvolverFactory< ? super T > factory, final int direction ) { this.factory = factory; this.direction = direction; } + @Deprecated + @Override + public void setExecutor( ExecutorService executor ) + { + this.executor = executor; + } + @Override public Interval requiredSourceInterval( final Interval targetInterval ) { @@ -84,104 +90,38 @@ public Interval requiredSourceInterval( final Interval targetInterval ) @Override public T preferredSourceType( final T targetType ) { - return (T) factory.preferredSourceType( targetType ); + return Cast.unchecked( factory.preferredSourceType( targetType ) ); } @Override - protected void process( final RandomAccessible< ? extends T > source, final RandomAccessibleInterval< ? extends T > target, final ExecutorService executorService, final int numThreads ) + public void process( RandomAccessible< ? extends T > source, RandomAccessibleInterval< ? extends T > target ) { final RandomAccessibleInterval< ? extends T > sourceInterval = Views.interval( source, requiredSourceInterval( target ) ); final long[] sourceMin = Intervals.minAsLongArray( sourceInterval ); final long[] targetMin = Intervals.minAsLongArray( target ); - final Supplier< Consumer< Localizable > > actionFactory = () -> { - - final RandomAccess< ? extends T > in = sourceInterval.randomAccess(); - final RandomAccess< ? extends T > out = target.randomAccess(); - final Runnable convolver = factory.getConvolver( in, out, direction, target.dimension( direction ) ); - - return position -> { - in.setPosition( sourceMin ); - out.setPosition( targetMin ); - in.move( position ); - out.move( position ); - convolver.run(); - }; - }; - final long[] dim = Intervals.dimensionsAsLongArray( target ); dim[ direction ] = 1; - final int numTasks = numThreads > 1 ? timesFourAvoidOverflow(numThreads) : 1; - LineConvolution.forEachIntervalElementInParallel( executorService, numTasks, new FinalInterval( dim ), actionFactory ); - } + RandomAccessibleInterval< Localizable > positions = Localizables.randomAccessibleInterval( new FinalInterval( dim ) ); + TaskExecutor taskExecutor = executor == null ? Parallelization.getTaskExecutor() : TaskExecutors.forExecutorService( executor ); + LoopBuilder.setImages( positions ).multiThreaded(taskExecutor).forEachChunk( + chunk -> { - private int timesFourAvoidOverflow( int x ) - { - return (int) Math.min((long) x * 4, Integer.MAX_VALUE); - } + final RandomAccess< ? extends T > in = sourceInterval.randomAccess(); + final RandomAccess< ? extends T > out = target.randomAccess(); + final Runnable convolver = factory.getConvolver( in, out, direction, target.dimension( direction ) ); - /** - * {@link #forEachIntervalElementInParallel(ExecutorService, int, Interval, Supplier)} - * executes a given action for each position in a given interval. Therefor - * it starts the specified number of tasks. Each tasks calls the action - * factory once, to get an instance of the action that should be executed. - * The action is then called multiple times by the task. - * - * @param service - * {@link ExecutorService} used to create the tasks. - * @param numTasks - * number of tasks to use. - * @param interval - * interval to iterate over. - * @param actionFactory - * factory that returns the action to be executed. - */ - // TODO: move to a better place - public static void forEachIntervalElementInParallel( final ExecutorService service, final int numTasks, final Interval interval, - final Supplier< Consumer< Localizable > > actionFactory ) - { - final long[] min = Intervals.minAsLongArray( interval ); - final long[] dim = Intervals.dimensionsAsLongArray( interval ); - final long size = Intervals.numElements( dim ); - final int boundedNumTasks = (int) Math.max( 1, Math.min(size, numTasks )); - final long taskSize = ( size - 1 ) / boundedNumTasks + 1; // taskSize = roundUp(size / boundedNumTasks); - final ArrayList< Callable< Void > > callables = new ArrayList<>(); + chunk.forEachPixel( position -> { + in.setPosition( sourceMin ); + out.setPosition( targetMin ); + in.move( position ); + out.move( position ); + convolver.run(); + } ); - for ( int taskNum = 0; taskNum < boundedNumTasks; ++taskNum ) - { - final long myStartIndex = taskNum * taskSize; - final long myEndIndex = Math.min( size, myStartIndex + taskSize ); - final Callable< Void > r = () -> { - final Consumer< Localizable > action = actionFactory.get(); - final long[] position = new long[ dim.length ]; - final Localizable localizable = Point.wrap( position ); - for ( long index = myStartIndex; index < myEndIndex; ++index ) - { - IntervalIndexer.indexToPositionWithOffset( index, dim, min, position ); - action.accept( localizable ); + return null; } - return null; - }; - callables.add( r ); - } - execute( service, callables ); - } - - private static void execute( final ExecutorService service, final ArrayList< Callable< Void > > callables ) - { - try - { - final List< Future< Void > > futures = service.invokeAll( callables ); - for ( final Future< Void > future : futures ) - future.get(); - } - catch ( final InterruptedException | ExecutionException e ) - { - final Throwable cause = e.getCause(); - if ( cause instanceof RuntimeException ) - throw ( RuntimeException ) cause; - throw new RuntimeException( e ); - } + ); } } diff --git a/src/main/java/net/imglib2/algorithm/convolution/MultiDimensionConvolution.java b/src/main/java/net/imglib2/algorithm/convolution/MultiDimensionConvolution.java index faef925c7..54a6bc633 100644 --- a/src/main/java/net/imglib2/algorithm/convolution/MultiDimensionConvolution.java +++ b/src/main/java/net/imglib2/algorithm/convolution/MultiDimensionConvolution.java @@ -53,6 +53,7 @@ public class MultiDimensionConvolution< T > implements Convolution< T > { private ExecutorService executor; + @Deprecated @Override public void setExecutor( final ExecutorService executor ) { diff --git a/src/main/java/net/imglib2/algorithm/gauss3/Gauss3.java b/src/main/java/net/imglib2/algorithm/gauss3/Gauss3.java index 0d17f73b7..17b9f2030 100644 --- a/src/main/java/net/imglib2/algorithm/gauss3/Gauss3.java +++ b/src/main/java/net/imglib2/algorithm/gauss3/Gauss3.java @@ -43,6 +43,7 @@ import net.imglib2.algorithm.convolution.kernel.Kernel1D; import net.imglib2.algorithm.convolution.kernel.SeparableKernelConvolution; import net.imglib2.exception.IncompatibleTypeException; +import net.imglib2.parallel.Parallelization; import net.imglib2.type.numeric.NumericType; import net.imglib2.type.numeric.RealType; import net.imglib2.type.numeric.real.DoubleType; @@ -126,10 +127,9 @@ public static < S extends NumericType< S >, T extends NumericType< T > > void ga */ public static < S extends NumericType< S >, T extends NumericType< T > > void gauss( final double[] sigma, final RandomAccessible< S > source, final RandomAccessibleInterval< T > target ) throws IncompatibleTypeException { - final int numthreads = Runtime.getRuntime().availableProcessors(); - final ExecutorService service = Executors.newFixedThreadPool( numthreads ); - gauss( sigma, source, target, service ); - service.shutdown(); + final double[][] halfkernels = halfkernels( sigma ); + final Convolution< NumericType< ? > > convolution = SeparableKernelConvolution.convolution( Kernel1D.symmetric( halfkernels ) ); + convolution.process( source, target ); } /** @@ -201,10 +201,9 @@ public static < S extends NumericType< S >, T extends NumericType< T > > void ga */ public static < S extends NumericType< S >, T extends NumericType< T > > void gauss( final double[] sigma, final RandomAccessible< S > source, final RandomAccessibleInterval< T > target, final ExecutorService service ) throws IncompatibleTypeException { - final double[][] halfkernels = halfkernels( sigma ); - final Convolution< NumericType< ? > > convolution = SeparableKernelConvolution.convolution( Kernel1D.symmetric( halfkernels ) ); - convolution.setExecutor( service ); - convolution.process( source, target ); + Parallelization.runWithExecutor( service, + () -> gauss( sigma, source, target ) + ); } public static double[][] halfkernels( final double[] sigma ) diff --git a/src/test/java/net/imglib2/algorithm/convolution/ConcatenationTest.java b/src/test/java/net/imglib2/algorithm/convolution/ConcatenationTest.java index ab9d78fa8..a893fd563 100644 --- a/src/test/java/net/imglib2/algorithm/convolution/ConcatenationTest.java +++ b/src/test/java/net/imglib2/algorithm/convolution/ConcatenationTest.java @@ -37,11 +37,8 @@ import net.imglib2.Interval; import net.imglib2.RandomAccessible; import net.imglib2.RandomAccessibleInterval; -import net.imglib2.algorithm.convolution.kernel.SeparableKernelConvolution; import net.imglib2.img.Img; -import net.imglib2.img.ImgFactory; import net.imglib2.img.array.ArrayImgs; -import net.imglib2.img.cell.CellImgFactory; import net.imglib2.loops.LoopBuilder; import net.imglib2.type.numeric.RealType; import net.imglib2.type.numeric.integer.IntType; @@ -51,6 +48,7 @@ import net.imglib2.util.Intervals; import net.imglib2.view.IntervalView; import net.imglib2.view.Views; +import org.junit.Ignore; import org.junit.Test; import static org.junit.Assert.assertArrayEquals; @@ -88,6 +86,7 @@ public void testDifferences2() assertArrayEquals( new int[] { -3, 3 }, targetPixels ); } + @Ignore( "takes to long" ) @Test public void testHugeImage() { @@ -96,7 +95,7 @@ public void testHugeImage() assertTrue( width * height > Integer.MAX_VALUE ); RandomAccessible< UnsignedByteType > source = ConstantUtils.constantRandomAccessible( new UnsignedByteType(), 2 ); RandomAccessibleInterval< UnsignedByteType > target = ConstantUtils.constantRandomAccessibleInterval( - new UnsignedByteType(), 2, new FinalInterval( width, height ) ); + new UnsignedByteType(), new FinalInterval( width, height ) ); double[][] kernels = { { 2 }, { 3 } }; try { diff --git a/src/test/java/net/imglib2/algorithm/convolution/LineConvolutionTest.java b/src/test/java/net/imglib2/algorithm/convolution/LineConvolutionTest.java index c69fd972d..6f76c5930 100644 --- a/src/test/java/net/imglib2/algorithm/convolution/LineConvolutionTest.java +++ b/src/test/java/net/imglib2/algorithm/convolution/LineConvolutionTest.java @@ -37,6 +37,8 @@ import net.imglib2.RandomAccess; import net.imglib2.img.Img; import net.imglib2.img.array.ArrayImgs; +import net.imglib2.parallel.Parallelization; +import net.imglib2.parallel.TaskExecutors; import net.imglib2.type.numeric.integer.UnsignedByteType; import net.imglib2.util.Intervals; import org.junit.Test; @@ -85,8 +87,11 @@ public void testNumTasksEqualsIntegerMaxValue() { byte[] result = new byte[ 1 ]; Img< UnsignedByteType > out = ArrayImgs.unsignedBytes( result, result.length ); Img< UnsignedByteType > in = ArrayImgs.unsignedBytes( new byte[] { 1, 2 }, 2 ); - final LineConvolution< UnsignedByteType > convolution = new LineConvolution<>( new ForwardDifferenceConvolverFactory(), 0 ); - convolution.process( in, out, Executors.newSingleThreadExecutor(), Integer.MAX_VALUE ); + Runnable runnable = () -> { + final LineConvolution< UnsignedByteType > convolution = new LineConvolution<>( new ForwardDifferenceConvolverFactory(), 0 ); + convolution.process( in, out ); + }; + Parallelization.runWithExecutor( TaskExecutors.forExecutorServiceAndNumTasks( Executors.newSingleThreadExecutor(), Integer.MAX_VALUE) , runnable ); assertArrayEquals( new byte[] { 1 }, result ); } From 425b05709039a8099606870607f42970f0511a6a Mon Sep 17 00:00:00 2001 From: Matthias Arzt Date: Fri, 5 Nov 2021 15:13:58 +0100 Subject: [PATCH 2/3] Add benchmark for Gauss3 on a small image --- .../algorithm/gauss3/Gauss3Benchmark.java | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 src/test/java/net/imglib2/algorithm/gauss3/Gauss3Benchmark.java diff --git a/src/test/java/net/imglib2/algorithm/gauss3/Gauss3Benchmark.java b/src/test/java/net/imglib2/algorithm/gauss3/Gauss3Benchmark.java new file mode 100644 index 000000000..bd26826af --- /dev/null +++ b/src/test/java/net/imglib2/algorithm/gauss3/Gauss3Benchmark.java @@ -0,0 +1,80 @@ +/*- + * #%L + * ImgLib2: a general-purpose, multidimensional image processing library. + * %% + * Copyright (C) 2009 - 2021 Tobias Pietzsch, Stephan Preibisch, Stephan Saalfeld, + * John Bogovic, Albert Cardona, Barry DeZonia, Christian Dietz, Jan Funke, + * Aivar Grislis, Jonathan Hale, Grant Harris, Stefan Helfrich, Mark Hiner, + * Martin Horn, Steffen Jaensch, Lee Kamentsky, Larry Lindsey, Melissa Linkert, + * Mark Longair, Brian Northan, Nick Perry, Curtis Rueden, Johannes Schindelin, + * Jean-Yves Tinevez and Michael Zinsmaier. + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package net.imglib2.algorithm.gauss3; + +import net.imglib2.img.Img; +import net.imglib2.img.array.ArrayImgs; +import net.imglib2.parallel.Parallelization; +import net.imglib2.type.numeric.real.DoubleType; +import net.imglib2.view.Views; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.util.concurrent.TimeUnit; + +/** + * Measure the time own execution of {@link Gauss3#gauss}. + */ +@Fork( 1 ) +@State( Scope.Benchmark ) +@Warmup( iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement( iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS ) +@BenchmarkMode( Mode.AverageTime ) +@OutputTimeUnit( TimeUnit.MILLISECONDS ) +public class Gauss3Benchmark +{ + + private double sigma = 2.0; + + private Img source = ArrayImgs.doubles( 100, 100 ); + + private Img target = ArrayImgs.doubles( 100, 100 ); + + @Benchmark + public void benchmark() + { + Gauss3.gauss( sigma, Views.extendBorder( source ), target); + } + + public static void main( String[] args ) throws RunnerException + { + Options opt = new OptionsBuilder() + .include( Gauss3Benchmark.class.getSimpleName() ) + .build(); + new Runner( opt ).run(); + } +} From 41e55dcf6279d177f7e1dc9e374a891fc8252e64 Mon Sep 17 00:00:00 2001 From: Matthias Arzt Date: Tue, 9 Nov 2021 09:54:25 +0100 Subject: [PATCH 3/3] Gauss3: update javadoc and mark some methods as deprecated. --- .../net/imglib2/algorithm/gauss3/Gauss3.java | 56 ++++++++++++++++--- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/imglib2/algorithm/gauss3/Gauss3.java b/src/main/java/net/imglib2/algorithm/gauss3/Gauss3.java index 17b9f2030..569effbc1 100644 --- a/src/main/java/net/imglib2/algorithm/gauss3/Gauss3.java +++ b/src/main/java/net/imglib2/algorithm/gauss3/Gauss3.java @@ -34,8 +34,10 @@ package net.imglib2.algorithm.gauss3; +import java.util.Arrays; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.ForkJoinPool; import net.imglib2.RandomAccessible; import net.imglib2.RandomAccessibleInterval; @@ -57,7 +59,7 @@ public final class Gauss3 { /** - * Apply Gaussian convolution to source and write the result to output. + * Apply Gaussian convolution to source and write the result to target. * In-place operation (source==target) is supported. * *

@@ -67,6 +69,11 @@ public final class Gauss3 * in their own precision. The source type S and target type T are either * both {@link RealType RealTypes} or both the same type. * + *

+ * Computation may be multi-threaded, according to the current + * {@link Parallelization} context. (By default, it will use the + * {@link ForkJoinPool#commonPool() common ForkJoinPool}) + * * @param sigma * standard deviation of isotropic Gaussian. * @param source @@ -94,7 +101,7 @@ public static < S extends NumericType< S >, T extends NumericType< T > > void ga } /** - * Apply Gaussian convolution to source and write the result to output. + * Apply Gaussian convolution to source and write the result to target. * In-place operation (source==target) is supported. * *

@@ -105,9 +112,10 @@ public static < S extends NumericType< S >, T extends NumericType< T > > void ga * both {@link RealType RealTypes} or both the same type. * *

- * Computation is multi-threaded with as many threads as processors - * available. - * + * Computation may be multi-threaded, according to the current + * {@link Parallelization} context. (By default, it will use the + * {@link ForkJoinPool#commonPool() common ForkJoinPool}) + * * @param sigma * standard deviation in every dimension. * @param source @@ -133,6 +141,21 @@ public static < S extends NumericType< S >, T extends NumericType< T > > void ga } /** + * @deprecated + * Deprecated. Please use + * {@link Gauss3#gauss(double, RandomAccessible, RandomAccessibleInterval) + * gauss(sigma, source, target)} instead. The number of threads used to + * calculate the Gaussion convolution may by set with the + * {@link Parallelization} context, as show in this example: + *

+	 * {@code
+	 * Parallelization.runWithNumThreads( numThreads,
+	 *    () -> gauss( sigma, source, target )
+	 * );
+	 * }
+	 * 
+ * + *

* Apply Gaussian convolution to source and write the result to output. * In-place operation (source==target) is supported. * @@ -162,14 +185,30 @@ public static < S extends NumericType< S >, T extends NumericType< T > > void ga * if source and target type are not compatible (they must be * either both {@link RealType RealTypes} or the same type). */ + @Deprecated public static < S extends NumericType< S >, T extends NumericType< T > > void gauss( final double[] sigma, final RandomAccessible< S > source, final RandomAccessibleInterval< T > target, final int numThreads ) throws IncompatibleTypeException { - final ExecutorService service = Executors.newFixedThreadPool( numThreads ); - gauss( sigma, source, target, service ); - service.shutdown(); + Parallelization.runWithNumThreads( numThreads, + () -> gauss( sigma, source, target ) + ); } /** + * @deprecated + * Deprecated. Please use + * {@link Gauss3#gauss(double, RandomAccessible, RandomAccessibleInterval) + * gauss(sigma, source, target)} instead. The ExecutorService used to + * calculate the Gaussion convolution may by set with the + * {@link Parallelization} context, as show in this example: + *

+	 * {@code
+	 * Parallelization.runWithExecutor( executorService,
+	 *    () -> gauss( sigma, source, target )
+	 * );
+	 * }
+	 * 
+ * + *

* Apply Gaussian convolution to source and write the result to output. * In-place operation (source==target) is supported. * @@ -199,6 +238,7 @@ public static < S extends NumericType< S >, T extends NumericType< T > > void ga * if source and target type are not compatible (they must be * either both {@link RealType RealTypes} or the same type). */ + @Deprecated public static < S extends NumericType< S >, T extends NumericType< T > > void gauss( final double[] sigma, final RandomAccessible< S > source, final RandomAccessibleInterval< T > target, final ExecutorService service ) throws IncompatibleTypeException { Parallelization.runWithExecutor( service,