Skip to content

Instantly share code, notes, and snippets.

@maarzt
Created May 11, 2020 14:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maarzt/eddc7901572e2b17baa5b71547f439cf to your computer and use it in GitHub Desktop.
Save maarzt/eddc7901572e2b17baa5b71547f439cf to your computer and use it in GitHub Desktop.
import net.imglib2.RandomAccessibleInterval;
import net.imglib2.img.array.ArrayImgs;
import net.imglib2.type.numeric.integer.IntType;
import net.imglib2.util.StopWatch;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Demonstration on how to use (and how not to use) multi-threaded LoopBuilder,
* to calculate the sum over all pixel of an image.
* <p>
* Calculating the sum over all pixels is a very simple task. But it's not
* so easy to do it in a thread-safe manner.
*/
public class LoopBuilderAndThreadSaftyDemo
{
public static void main(String... args) {
// Create an image that has 100 million pixels. All are pixels set to one.
final RandomAccessibleInterval<IntType> image = ArrayImgs.ints(1000, 1000, 100);
LoopBuilder.setImages( image ).forEachPixel( pixel -> pixel.set(1) );
// Calculate the sum over all pixels. (Correct result is 100 million. ;-)
// single threaded
sum_SingleThreaded(image);
// multi threaded
sum_OnChunks(image); // fastest
sum_Incorrect(image); // wrong
sum_WronglySyncronized(image); // wrong
sum_CorrectlySynchronized(image); // very slow, much slower than single-threaded
sum_AtomicInteger(image); // still slower than single threaded
// The console output I get running this:
// --------------------------------------
// Result: 100000000 calculation time: 255.370 ms
// Result: 100000000 calculation time: 93.168 ms
// Result: 15086584 calculation time: 395.261 ms // (wrong)
// Result: 13468709 calculation time: 335.830 ms // (wrong)
// Result: 100000000 calculation time: 6.064 s
// Result: 100000000 calculation time: 2.034 s
}
private static void sum_SingleThreaded( RandomAccessibleInterval< IntType > image )
{
StopWatch stopWatch = StopWatch.createAndStart();
IntType sum = new IntType();
LoopBuilder.setImages( image ).forEachPixel( pixel -> sum.add( pixel ) );
System.out.println( "Result: " + sum + " calculation time: " + stopWatch );
}
private static void sum_OnChunks( RandomAccessibleInterval< IntType > image )
{
StopWatch stopWatch = StopWatch.createAndStart();
List< IntType > sums = LoopBuilder.setImages( image ).multiThreaded().forEachChunk(
chunk -> {
IntType sum = new IntType();
chunk.forEachPixel( pixel -> sum.add( pixel ) );
return sum;
}
);
IntType totalSum = new IntType();
for ( IntType sum : sums )
totalSum.add( sum );
System.out.println( "Result: " + totalSum + " calculation time: " + stopWatch );
}
private static void sum_Incorrect( RandomAccessibleInterval< IntType > image )
{
StopWatch stopWatch = StopWatch.createAndStart();
/* wrong */ IntType sum = new IntType();
/* wrong */ LoopBuilder.setImages( image ).multiThreaded().forEachPixel( pixel -> sum.add( pixel ) );
System.out.println( "Result: " + sum + " calculation time: " + stopWatch );
}
private static void sum_WronglySyncronized( RandomAccessibleInterval< IntType > image )
{
StopWatch stopWatch = StopWatch.createAndStart();
/* wrong */ IntType sum = new IntType();
/* wrong */ synchronized ( sum )
/* wrong */ {
/* wrong */ LoopBuilder.setImages( image ).multiThreaded().forEachPixel( pixel -> sum.add( pixel ) );
/* wrong */ }
System.out.println( "Result: " + sum + " calculation time: " + stopWatch );
}
private static void sum_CorrectlySynchronized( RandomAccessibleInterval< IntType > image )
{
StopWatch stopWatch = StopWatch.createAndStart();
// VERY SLOW, using synchronized makes this very slow
IntType sum = new IntType();
LoopBuilder.setImages( image ).multiThreaded().forEachPixel( pixel -> {
synchronized ( sum )
{
sum.add( pixel );
}
} );
System.out.println( "Result: " + sum + " calculation time: " + stopWatch );
}
private static void sum_AtomicInteger( RandomAccessibleInterval< IntType > image )
{
StopWatch stopWatch = StopWatch.createAndStart();
// SLOW, using synchronized makes this very slow
AtomicInteger sum = new AtomicInteger();
LoopBuilder.setImages( image ).multiThreaded().forEachPixel( pixel -> {
sum.addAndGet( pixel.getInteger() );
} );
System.out.println( "Result: " + sum + " calculation time: " + stopWatch );
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment