Use of _GParsPool_ - the JSR-166y based concurrent collection processor

h2. Usage of GParsPool

The _GParsPool_ class enables a ParallelArray-based (from JSR-166y) concurrency DSL for collections and objects.

Examples of use:

{code}
 //summarize numbers concurrently
 GParsPool.withPool {
     final AtomicInteger result = new AtomicInteger(0)
     [1, 2, 3, 4, 5].eachParallel {result.addAndGet(it)}
     assert 15 == result
 }

 //multiply numbers asynchronously
 GParsPool.withPool {
     final List result = [1, 2, 3, 4, 5].collectParallel {it * 2}
     assert ([2, 4, 6, 8, 10].equals(result))
 }
{code}The passed-in closure takes an instance of a ForkJoinPool as a parameter, which can be then used freely inside the closure.
{code} //check whether all elements within a collection meet certain criteria
 GParsPool.withPool(5) {ForkJoinPool pool ->
     assert [1, 2, 3, 4, 5].everyParallel {it > 0}
     assert ![1, 2, 3, 4, 5].everyParallel {it > 1}
 }
{code}
The _GParsPool.withPool()_ method takes optional parameters for number of threads in the created pool and an unhandled exception handler.
{code}
withPool(10) {...}
withPool(20, exceptionHandler) {...}
{code}

The _GParsPool.withExistingPool()_ takes an already existing ForkJoinPool instance to reuse.
The DSL is valid only within the associated block of code and only for the thread that has called the _withPool()_ or _withExistingPool()_ methods. The _withPool()_ method returns only after all the worker threads have finished their tasks and the pool has been destroyed, returning back the return value of the associated block of code. The _withExistingPool()_ method doesn't wait for the pool threads to finish.

Alternatively, the _GParsPool_ class can be statically imported _import static groovyx.gpars.GParsPool.`*`_ , which will allow omitting the _GParsPool_ class name.
{code} withPool {
     assert [1, 2, 3, 4, 5].everyParallel {it > 0}
     assert ![1, 2, 3, 4, 5].everyParallel {it > 1}
 }
{code}

The following methods are currently supported on all objects in Groovy:
* eachParallel()
* eachWithIndexParallel()
* collectParallel()
* collectManyParallel()
* findAllParallel()
* findAnyParallel
* findParallel()
* everyParallel()
* anyParallel()
* grepParallel()
* groupByParallel()
* foldParallel()
* minParallel()
* maxParallel()
* sumParallel()
* splitParallel()
* countParallel()
* foldParallel()

h3. Meta-class enhancer

As an alternative you can use the _ParallelEnhancer_ class to enhance meta-classes of any classes or individual instances with the parallel methods.
{code}import groovyx.gpars.ParallelEnhancer

def list = [1, 2, 3, 4, 5, 6, 7, 8, 9]
ParallelEnhancer.enhanceInstance(list)
println list.collectParallel {it * 2 }

def animals = ['dog', 'ant', 'cat', 'whale']
ParallelEnhancer.enhanceInstance animals
println (animals.anyParallel {it ==~ /ant/} ? 'Found an ant' : 'No ants found')
println (animals.everyParallel {it.contains('a')} ? 'All animals contain a' : 'Some animals can live without an a')
{code}
When using the _ParallelEnhancer_ class, you're not restricted to a _withPool()_ block with the use of the GParsPool DSLs. The enhanced classed or instances
remain enhanced till they get garbage collected.

h3. Exception handling

If an exception is thrown while processing any of the passed-in closures, the first exception gets re-thrown from the xxxParallel methods and the algorithm stops as soon as possible.

{note}
The exception handling mechanism of GParsPool builds on the one built into the Fork/Join framework. Since Fork/Join algorithms are by nature hierarchical,
once any part of the algorithm fails, there's usually little benefit from continuing the computation, since some branches of the algorithm will never return a result.

Bear in mind that the GParsPool implementation doesn't give any guarantees about its behavior after a first unhandled exception occurs,
beyond stopping the algorithm and re-throwing the first detected exception to the caller.
This behavior, after all, is consistent with what the traditional sequential iteration methods do.
{note}

h3. Transparently parallel collections

On top of adding new xxxParallel() methods, *GPars* can also let you change the semantics of the original iteration methods. For example, you may be passing a collection into a library method, which will process your collection
in a sequential way, let say using the _collect()_ method. By changing the semantics of the _collect()_ method on your collection you can effectively parallelize the library sequential code.

{code}
GParsPool.withPool {

    //The selectImportantNames() will process the name collections concurrently
    assert ['ALICE', 'JASON'] == selectImportantNames(['Joe', 'Alice', 'Dave', 'Jason'].makeConcurrent())
}

/**
 * A function implemented using standard sequential collect() and findAll() methods.
 */
def selectImportantNames(names) {
    names.collect {it.toUpperCase()}.findAll{it.size() > 4}
}
{code}

The _makeSequential()_ method will reset the collection back to the original sequential semantics.

{code}
import static groovyx.gpars.GParsPool.withPool

def list = [1, 2, 3, 4, 5, 6, 7, 8, 9]

println 'Sequential: '
list.each { print it + ',' }
println()

withPool {

    println 'Sequential: '
    list.each { print it + ',' }
    println()

    list.makeConcurrent()

    println 'Concurrent: '
    list.each { print it + ',' }
    println()

    list.makeSequential()

    println 'Sequential: '
    list.each { print it + ',' }
    println()
}

println 'Sequential: '
list.each { print it + ',' }
println()
{code}

The _asConcurrent()_ convenience method will allow you to specify code blocks, in which the collection maintains concurrent semantics.

{code}
import static groovyx.gpars.GParsPool.withPool

def list = [1, 2, 3, 4, 5, 6, 7, 8, 9]

println 'Sequential: '
list.each { print it + ',' }
println()

withPool {

    println 'Sequential: '
    list.each { print it + ',' }
    println()

    list.asConcurrent {
        println 'Concurrent: '
        list.each { print it + ',' }
        println()
    }

    println 'Sequential: '
    list.each { print it + ',' }
    println()
}

println 'Sequential: '
list.each { print it + ',' }
println()
{code}

Transparent parallelizm, including the _makeConcurrent()_ , _makeSequential()_ and _asConcurrent()_ methods, is also available in combination with _ParallelEnhancer_ .
{code}
/**
 * A function implemented using standard sequential collect() and findAll() methods.
 */
def selectImportantNames(names) {
    names.collect {it.toUpperCase()}.findAll{it.size() > 4}
}

def names = ['Joe', 'Alice', 'Dave', 'Jason']
ParallelEnhancer.enhanceInstance(names)
//The selectImportantNames() will process the name collections concurrently
assert ['ALICE', 'JASON'] == selectImportantNames(names.makeConcurrent())

{code}

{code}
import groovyx.gpars.ParallelEnhancer

def list = [1, 2, 3, 4, 5, 6, 7, 8, 9]

println 'Sequential: '
list.each { print it + ',' }
println()

ParallelEnhancer.enhanceInstance(list)

println 'Sequential: '
list.each { print it + ',' }
println()

list.asConcurrent {
    println 'Concurrent: '
    list.each { print it + ',' }
    println()

}
list.makeSequential()

println 'Sequential: '
list.each { print it + ',' }
println()
{code}
h2. Avoid side-effects in functions

We have to warn you. Since the closures that are provided to the parallel methods like _eachParallel()_ or _collectParallel()_ may be run in parallel, you have to make sure that each of the closures
is written in a thread-safe manner. The closures must hold no internal state, share data nor have side-effects beyond the boundaries the single element that they've been invoked on.
Violations of these rules will open the door for race conditions and deadlocks, the most severe enemies of a modern multi-core programmer.

*Don't do this:*
{code}
def thumbnails = []
images.eachParallel {thumbnails << it.thumbnail}  //Concurrently accessing a not-thread-safe collection of thumbnails, don't do this!
{code}
At least, you've been warned.

{note}
Because _GParsPool_ uses a *Fork/Join* pool (with work stealing), threads may
not be applied to a waiting processing task even though they may appear
idle. With a work-stealing algorithm, worker threads that run out of things
to do can steal tasks from other threads that are still busy.

if you use _GParsExecutorsPool_ , which doesn't use *Fork/Join*, you get the
thread allocation behavior that you would naively expect.
{note}
