Use of GParsExecutorsPool - the Java Executors' based concurrent collection processor

h2. Usage of GParsExecutorsPool

The _GParsPool_ class enables a Java Executors-based concurrency DSL for collections and objects.

The _GParsExecutorsPool_ class can be used as a pure-JDK-based collection parallel processor. Unlike the _GParsPool_ class, _GParsExecutorsPool_ doesn't require jsr-166y jar file, but leverages the standard JDK executor services to parallelize closures processing a collections or an object iteratively.
It needs to be states, however, that _GParsPool_ performs typically much better than _GParsExecutorsPool_ does.

Examples of use:
{code} //multiply numbers asynchronously
 GParsExecutorsPool.withPool {
     Collection<Future> result = [1, 2, 3, 4, 5].collectParallel{it * 10}
     assert new HashSet([10, 20, 30, 40, 50]) == new HashSet((Collection)result*.get())
 }

 //multiply numbers asynchronously using an asynchronous closure
 GParsExecutorsPool.withPool {
     def closure={it * 10}
     def asyncClosure=closure.async()
     Collection<Future> result = [1, 2, 3, 4, 5].collect(asyncClosure)
     assert new HashSet([10, 20, 30, 40, 50]) == new HashSet((Collection)result*.get())
 }
{code}
The passed-in closure takes an instance of a ExecutorService as a parameter, which can be then used freely inside the closure.
{code} //find an element meeting specified criteria
 GParsExecutorsPool.withPool(5) {ExecutorService service ->
     service.submit({performLongCalculation()} as Runnable)
 }
{code}
The _GParsExecutorsPool.withPool()_ method takes optional parameters for number of threads in the created pool and a thread factory.
{code}
withPool(10) {...}
withPool(20, threadFactory) {...}
{code}

The _GParsExecutorsPool.withExistingPool()_ takes an already existing executor service 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()_ method. The _withPool()_ method returns only after all the worker threads have finished their tasks and the executor service has been destroyed, returning back the return value of the associated block of code. The _withExistingPool()_ method doesn't wait for the executor service threads to finish.

Alternatively, the _GParsExecutorsPool_ class can be statically imported _import static groovyx.gpars.GParsExecutorsPool.`*`_, which will allow omitting the _GParsExecutorsPool_ class name.
{code} withPool {
     def result = [1, 2, 3, 4, 5].findParallel{Number number -> number > 2}
     assert result in [3, 4, 5]
 }
{code}
The following methods on all objects, which support iterations in Groovy, are currently supported:
* eachParallel()
* eachWithIndexParallel()
* collectParallel()
* findAllParallel()
* findParallel()
* allParallel()
* anyParallel()
* grepParallel()
* groupByParallel()

h3. Meta-class enhancer

As an alternative you can use the _GParsExecutorsPoolEnhancer_ class to enhance meta-classes for any classes or individual instances with asynchronous methods.
{code}import groovyx.gpars.GParsExecutorsPoolEnhancer

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

def animals = ['dog', 'ant', 'cat', 'whale']
GParsExecutorsPoolEnhancer.enhanceInstance animals
println (animals.anyParallel {it ==~ /ant/} ? 'Found an ant' : 'No ants found')
println (animals.allParallel {it.contains('a')} ? 'All animals contain a' : 'Some animals can live without an a')
{code}

When using the _GParsExecutorsPoolEnhancer_ class, you're not restricted to a _withPool()_ block with the use of the GParsExecutorsPool DSLs. The enhanced classed or instances
remain enhanced till they get garbage collected.

h3. Exception handling

If exceptions are thrown while processing any of the passed-in closures, an instance of _AsyncException_ wrapping all the original exceptions gets re-thrown from the xxxParallel methods.

h2. Avoid side-effects in functions

Once again we need to warn you about using closures with side-effects effecting objects beyond the scope of the single currently processed element or closures which keep state. Don't do that! It is dangerous to pass them to any of the _xxxParallel()_ methods.
