
groovyx.gpars.GParsExecutorsPool.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gpars Show documentation
Show all versions of gpars Show documentation
The Groovy and Java high-level concurrency library offering actors, dataflow, CSP, agents, parallel collections, fork/join and more
// GPars - Groovy Parallel Systems
//
// Copyright © 2008-11 The original author or authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package groovyx.gpars
import groovyx.gpars.dataflow.DataflowVariable
import groovyx.gpars.util.PoolUtils
import java.util.concurrent.Callable
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.concurrent.Future
import java.util.concurrent.ThreadFactory
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger
/**
* Enables a ExecutorService-based DSL on closures, objects and collections.
* E.g.
* GParsExecutorsPool.withPool(5) {ExecutorService service ->
* Collection result = [1, 2, 3, 4, 5].collectParallel({it * 10}.async())
* assertEquals(new HashSet([10, 20, 30, 40, 50]), new HashSet((Collection)result*.get()))
*}*
* GParsExecutorsPool.withPool(5) {ExecutorService service ->
* def result = [1, 2, 3, 4, 5].findParallel{Number number -> number > 2}* assert result in [3, 4, 5]
*}*
* @author Vaclav Pech
* Date: Oct 23, 2008
*/
class GParsExecutorsPool {
/**
* Maps threads to their appropriate thread pools
*/
private static final ThreadLocalPools currentPoolStack = new ThreadLocalPools()
/**
* Caches the default pool size.
*/
private static final int defaultPoolSize = PoolUtils.retrieveDefaultPoolSize()
/**
* Retrieves the pool assigned to the current thread.
*/
protected static ExecutorService retrieveCurrentPool() {
currentPoolStack.current
}
/**
* Creates a new pool with the default size()
*/
private static createPool() {
return createPool(PoolUtils.retrieveDefaultPoolSize())
}
/**
* Creates a new pool with the given size()
*/
private static createPool(int poolSize) {
return createPool(poolSize, createDefaultThreadFactory())
}
private static createPool(int poolSize, ThreadFactory threadFactory) {
if (!(poolSize in 1..Integer.MAX_VALUE)) throw new IllegalArgumentException("Invalid value $poolSize for the pool size has been specified. Please supply a positive int number.")
if (!threadFactory) throw new IllegalArgumentException("No value specified for threadFactory.")
return Executors.newFixedThreadPool(poolSize, threadFactory)
}
private static ThreadFactory createDefaultThreadFactory() {
return {Runnable runnable ->
final Thread thread = new Thread(runnable)
thread.daemon = false
thread
} as ThreadFactory
}
/**
* Creates a new instance of ExecutorService, binds it to the current thread, enables the ExecutorService DSL
* and runs the supplied closure.
* It is an identical alternative for withPool() with a shorter name.
* Within the supplied code block the ExecutorService is available as the only parameter, objects have been
* enhanced with the eachParallel(), collectParallel() and other methods from the GParsExecutorsPoolUtil
* category class as well as closures can be turned into asynchronous ones by calling the async() method on them.
* E.g. closure,async returns a new closure, which, when run will schedule the original closure
* for processing in the pool.
* Calling images.eachParallel{processImage(it}} will call the potentially long-lasting processImage()
* operation on each image in the images collection in parallel.
*
* def result = new ConcurrentSkipListSet()
* GParsExecutorsPool.withPool {ExecutorService service ->
* [1, 2, 3, 4, 5].eachParallel{Number number -> result.add(number * 10)}* assertEquals(new HashSet([10, 20, 30, 40, 50]), result)
*}*
* @param cl The block of code to invoke with the DSL enabled
*/
public static withPool(Closure cl) {
return withPool(defaultPoolSize, cl)
}
/**
* Creates a new instance of ExecutorService, binds it to the current thread, enables the ExecutorService DSL
* and runs the supplied closure.
* It is an identical alternative for withPool() with a shorter name.
* Within the supplied code block the ExecutorService is available as the only parameter, objects have been
* enhanced with the eachParallel(), collectParallel() and other methods from the GParsExecutorsPoolUtil
* category class as well as closures can be turned into asynchronous ones by calling the async() method on them.
* E.g. closure,async returns a new closure, which, when run will schedule the original closure
* for processing in the pool.
* Calling images.eachParallel{processImage(it}} will call the potentially long-lasting processImage()
* operation on each image in the images collection in parallel.
*
* def result = new ConcurrentSkipListSet()
* GParsExecutorsPool.withPool(5) {ExecutorService service ->
* [1, 2, 3, 4, 5].eachParallel{Number number -> result.add(number * 10)}* assertEquals(new HashSet([10, 20, 30, 40, 50]), result)
*}*
* @param numberOfThreads Number of threads in the newly created thread pool
* @param cl The block of code to invoke with the DSL enabled
*/
public static withPool(int numberOfThreads, Closure cl) {
return withPool(numberOfThreads, createDefaultThreadFactory(), cl)
}
/**
* Creates a new instance of ExecutorService, binds it to the current thread, enables the ExecutorService DSL
* and runs the supplied closure.
* It is an identical alternative for withPool() with a shorter name.
* Within the supplied code block the ExecutorService is available as the only parameter, objects have been
* enhanced with the eachParallel(), collectParallel() and other methods from the GParsExecutorsPoolUtil
* category class as well as closures can be turned into asynchronous ones by calling the async() method on them.
* E.g. closure,async returns a new closure, which, when run will schedule the original closure
* for processing in the pool.
* Calling images.eachParallel{processImage(it}} will call the potentially long-lasting processImage()
* operation on each image in the images collection in parallel.
*
* def result = new ConcurrentSkipListSet()
* GParsExecutorsPool.withPool(5) {ExecutorService service ->
* [1, 2, 3, 4, 5].eachParallel{Number number -> result.add(number * 10)}* assertEquals(new HashSet([10, 20, 30, 40, 50]), result)
*}*
* @param numberOfThreads Number of threads in the newly created thread pool
* @param threadFactory Factory for threads in the pool
* @param cl The block of code to invoke with the DSL enabled
*/
public static withPool(int numberOfThreads, ThreadFactory threadFactory, Closure cl) {
final ExecutorService pool = createPool(numberOfThreads, threadFactory)
try {
return withExistingPool(pool, cl)
} finally {
pool.shutdown()
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS)
}
}
/**
* Creates a new instance of ExecutorService, binds it to the current thread, enables the ExecutorService DSL
* and runs the supplied closure.
* Within the supplied code block the ExecutorService is available as the only parameter, objects have been
* enhanced with the eachParallel(), collectParallel() and other methods from the GParsExecutorsPoolUtil
* category class as well as closures can be turned into asynchronous ones by calling the async() method on them.
* E.g. closure,async returns a new closure, which, when run will schedule the original closure
* for processing in the pool.
* Calling images.eachParallel{processImage(it}} will call the potentially long-lasting processImage()
* operation on each image in the images collection in parallel.
*
* def result = new ConcurrentSkipListSet()
* GParsExecutorsPool.withPool(5) {ExecutorService service ->
* [1, 2, 3, 4, 5].eachParallel{Number number -> result.add(number * 10)}* assertEquals(new HashSet([10, 20, 30, 40, 50]), result)
*}*
* @param pool The ExecutorService to use, the service will not be shutdown after this method returns
*/
public static withExistingPool(ExecutorService pool, Closure cl) {
currentPoolStack << pool
def result = null
try {
use(GParsExecutorsPoolUtil) {
result = cl(pool)
}
} finally {
currentPoolStack.pop()
}
return result
}
/**
* Starts multiple closures in separate threads, collecting their return values
* If an exception is thrown from the closure when called on any of the collection's elements,
* it will be re-thrown in the calling thread when it calls the Future.get() method.
* @return The result values of all closures
* @throws AsyncException If any of the collection's elements causes the closure to throw an exception. The original exceptions will be stored in the AsyncException's concurrentExceptions field.
*/
public static List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy