Class TiledProcess<R>

java.lang.Object
org.apache.sis.internal.processing.image.TiledProcess<R>
Type Parameters:
R - the type of value computed as a result of this process.
Direct Known Subclasses:
Parallelized

public abstract class TiledProcess<R> extends Object
Calculation in a two-dimensional space that can be subdivided in smaller calculations in sub-regions. This class manages a kind of fork-join task but differs from ForkJoinPool in the following aspects:
  • The fork and join processes are presumed relatively costly (i.e. they may need to reconstruct geometries splitted in two consecutive tiles). So instead of having many medium tasks waiting for a thread to take them, it may be more efficient to have fewer tasks processing larger areas. TiledProcess tries to create a number of sub-tasks close to the number of processors. This is a different approach than "work stealing" algorithm applied by JDK ForkJoinPool, which is designed for smaller (and more easily separable) non-blocking tasks.
  • The main task is splitted in sub-tasks with a single fork step, with two division factors along x and y axes which can be any integer (not necessarily powers of 2). This is a different approach than JDK ForkJoinPool where tasks are forked recursively in two sub-tasks at each step.
  • The join operation tries to operate on tiles that are neighbors in the two dimensional space. It allows the join operation to merge geometries that are splited between two tiles.
  • Tasks may block on I/O operations. We want to avoid blocking the JDK common fork/join pool, so we use a separated pool.
The tiling applied by TiledProcess is independent of RenderedImage tiling. This class assumes that the objects to be calculated are geometries or other non-raster data. Consequently, tile size will be determined by other considerations such as the number of processors.
Since:
1.1
Version:
1.3
  • Field Details

    • MIN_TILE_SIZE

      private static final int MIN_TILE_SIZE
      Minimal "tile" size for sub-tasks computation. That size should not be too small because the fork/join processes have some extra cost compared to processing the whole image as one single tile.
      See Also:
    • runningThreads

      private final AtomicInteger runningThreads
      Number of threads that are running. This is used for knowing when a thread is the last one.
    • tasks

      private final TiledProcess<R>.Task[] tasks
      All tasks executed in parallel threads. The array length should be less than the number of processors. All read and write accesses to array elements must be done inside a synchronized(tasks) block.

      This array initially contains only null elements. Non-null elements are assigned after TiledProcess.Task.execute() completion but before TiledProcess.Task.merge(Task).

    • yStride

      private final int yStride
      Number of tiles (or tasks) on the x axis. Used for computing (x,y) coordinates of elements in the tasks array, considering that the array is a matrix encoded in row-major fashion. This is the increment to apply on array index for incrementing the y coordinate by one.
    • taskIndex

      private int taskIndex
      Index of this TiledProcess instance in the tasks array. This is a temporary variable for TiledProcess.Task.index initialization only.
    • iterators

      private PixelIterator[] iterators
      Iterator over the pixel for each element in the tasks array. This is a temporary variable for TiledProcess.Task.iterator initialization only.
  • Constructor Details

    • TiledProcess

      protected TiledProcess(RenderedImage data, int overlapX, int overlapY, PixelIterator.Builder iteratorFactory)
      Prepares TiledProcess for execution of a task splitted in different regions. This constructor splits the given image in sub-regions ("tiles" but not in the sense of RenderedImage tiles), then creates a pixel iterator for each sub-region. Iterators are created with the given PixelIterator.Builder, which should be configured by the caller in all desired aspects (e.g. iteration order) except the region of interest, which will be overwritten by this method.

      Usage example:

      Parameters:
      data - the image on which to iterate over the pixels.
      overlapX - the number of overlapping pixels between tiles on the x axis.
      overlapY - the number of overlapping pixels between tiles on the y axis.
      iteratorFactory - a pre-configured (except for sub-region aspect) supplier of pixel iterators.
      Throws:
      ArithmeticException - if the image size is too large.
  • Method Details

    • execute

      public final Future<R> execute()
      Starts execution of each sub-task in its own thread.
      Returns:
      a Future representing pending completion of the task.
    • createSubTask

      protected abstract TiledProcess<R>.Task createSubTask()
      Creates a sub-task doing the computation on a sub-region of the image. This method is invoked by execute() for each "tile" where the sub-task will be executed. Each sub-tasks will have its own pixel iterator.
      Returns:
      a sub-task over a sub-region of the image to process.