5. Problems with Java Concurrency Model
Synchronization
Dead-Locks
Live-Locks
Race Conditions
Starvation
6. GPars GOAL
To fully utilize all available processors
7. What is GPars ?
An open-source concurrency and parallelism
library for Groovy and Java
Gives a number of high-level abstractions for
writing concurrent and parallel code
Abstractions like..
Map-Reduce
Fork-Join
Asynchronous Closures
Actors
Agents
DataFlow
9. Data Parallelism
For low level data parallelism techniques
GParsPool – Relies on JSR-166y Fork/Join
Framework and offers greater functionality and
better performance.
GParsExecutorsPool – Uses old Java executors and
so is easy to setup in a managed or restricted
environment.
10. Data Parallelism – Parallel Collections
Dealing with data frequently involves
manipulating collections
Lists, arrays, sets, maps, iterators, strings etc.
can be viewed as collections of items
Common pattern to process such collections is to
take elements sequentially, one-by-one, and
make an action for each of the items in row.
E.g min() function – Iterates over the collection
sequentially to find the minimum value
11. Parallel Collections with GParsPool
The GParsPool class enables a ParallelArray-based
(from JSR-166y) concurrency DSL for collections
and objects.
GParsPool.withPool(){ .. }
GParsPool.withPool(){ ForkJoinPool pool ->.. }
GParsPool.withPool(10){ .. }
GParsPool.withExistingPool(ForkJoinPool pool){ .. }
12. Parallel Collections with GParsPool
Some of the methods supported are -
eachParallel()
collectParallel()
findAllParallel()
findAnyParallel()
groupByParallel()
minParallel()
maxParallel()
sumParallel()
countParallel()
13. Parallel Collections with Meta-class enhancer
ParallelEnhancer
def list = [1,2,3,4,5,6,7,8]
ParallelEnhancer.enhanceInstance(list)
println list.collectParallel{it * 2}
14. Parallel Collections with Meta-class enhancer
ParallelEnhancer
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 a')
15. Parallel Collections – Warning
Don't do this
def thumbnails = []
images.eachParallel{
thumbnails << it.thumbnail
}
16. Parallel Collections - Memoize
Enables caching of function's return values.
Repeated calls to the memoized function will
retrieve the result value from an internal
transparent cache.
Example
17. Data Parallelism – Map Reduce
Can be used for the same purpose as the
xxxParallel() family methods and has very similar
semantics.
Can perform considerably faster if you need to
chain multiple methods to process a single
collection in multiple steps.
Example
18. Data Parallelism – Map Reduce
How it is different from Parallel Collections
The xxxParallel() methods must return a legal collection of items.
Internally they build ParallelArray, perform required operation
concurrently and destroy ParallelArray before returning
Repeats same process for every xxxParallel() method call.
With Map-Reduce Parallel Array is created just once and same is
used in all chained method calls.
To get collection, retrieve "collection" property
19. Data Parallelism – Asynchronous Invocation
async() - Creates an asynchronous variant of the
supplied closure
GParsPool.withPool{
Closure longLastingCalculation = {calculate()}
Closure fastCalculation =
longLastingCalculation.async()
Future result = fastCalculation()
//do stuff while calculation performs...
println result.get()
}
20. Data Parallelism – Asynchronous Invocation
callAsync() - Calls a closure in a separate thread
supplying the given arguments
GParsPool.withPool{
println ({it * 2}.call(3))
println ({it * 2}.callAsync(3).get())
}
22. Actors
Was originally inspired by the Actors library in
Scala
Allow for a message passing-based concurrency
model
Programs are collections of independent active
objects that exchange messages and have no
mutable shared state
Always guarantee that at most one thread
processes the actor's body
23. Actors
Helps to avoid deadlock, live-lock and starvation
A great number of actors can share a relatively
small thread pool
An actor with no work doesn't consume threads.
No shared mutable state.
Runs in daemon threads.
25. Actors - Types
Stateless Actors
DynamicDispatchActor and Reactive Actor
Keep no track of what messages have arrived previously
Stateful Actors
DefaultActor
Allows user to handle implicit state directly
After receiving a message the actor moves into a new state
with different ways to handle future messages
E.g Encrypted messages for decryption, only after it has
received the encryption keys
26. Stateful Actors
Can be created in one of two ways
By extending DefaultActor class
Static methods of Actors class
27. Actors - Usage
Performs 3 specific operations
Send Messages
Receive Messages
Create new actors
28. Actors – Sending Messages
Messages can be sent to actors using
send() method
<< operator
Implicit call() method
34. Actors – Receiving Messages
react() method within Actor's code is responsible
to consume message from actor's inbox
react{message ->
//consume message...
}
Wait's if there is no message to be processed
immediately
Supplied closure is not invoked directly
Is scheduled for processing by any thread in the
thread pool once a message is available
36. Blocking Actors
Blocking actors hold a single pooled thread for
their whole life-time
Includes the time when waiting for messages
Avoids thread management overhead
The number of blocking actors running
concurrently is limited by the number of threads
available in the shared pool.
Provide better performance compared to
continuation-style actors
Good candidates for high-traffic positions in actor
network.
38. Stateless Actors
Dynamic Dispatch Actor
Repeatedly scans for messages
Dispatches arrived messages to one of the
onMessage(message) methods
Performance better than DefaultActor
40. Stateless Actors - DynamicDispatchActor
Actor myActor = new
DynamicDispatchActor().become{
when {String msg ->
println "Received String : $msg"
}
when {Integer msg ->
println "Received Integer : $msg"
}
}
41. Stateless Actor – Static Dispatch Actor
Contains single handler method
Performs better than DynamicDispatchActor
Make Dataflow operators four times faster
compared to when using DynamicDispatchActor
class MyActor extends StaticDispatchActor<String>{
void onMessage(String message){
println "Message is : $message"
}
}
43. Agents
Inspired by Agents in Clojure
Used when shared mutable state is required e.g
Shopping Cart
Is a thread-safe non-blocking shared mutable
state wrapper
Hides data and protects from direct access
Accepts messages and process them
asynchronously
44. Agents
Messages are commands(functions) and executed
inside Agent
Agent guarantees execution of a single function at
a time
After reception, received function is run against
the internal state of Agent and return value is new
internal state of Agent
The mutable values are not directly accessible
from outside
45. Agents
Requests have to be sent to Agent
Agent guarantees to process the requests
seqentially on behaf of callers
Wraps a reference to mutable state held inside a
single field
Messages can be sent via
'<<' operator
send() method
Implicit call() method
46. Agents - Basic Rules
Submitted commands obtain the agent's state as
a parameter.
Can call any methods on the agent's state.
Replacing the state object with a new one is also
possible using the updateValue() method.
The val property waits until all preceding
commands are consumed
47. Agents – Basic Rules
The valAsync() does not block caller.
The instantVal returns immediate snapshot of
agent state.
All Agent instances share a default daemon thread
pool.
Setting the threadPool property of an Agent
instance will allow it to use a different thread
pool.
49. Agent – Listeners & Validators
Listeners
Get notified each time internal state changes
Validators
Get a chance to reject a coming change by throwing an
exception
51. Dataflow
Operations in Dataflow programs consists of
“Black Boxes”
Inputs and Outputs are always explicitly defined
They run as soon as all of their inputs become
valid
Dataflow program is more like series of workers
in assembly line
They are inherently parallel
53. Dataflow Variables
Channel to safely and reliably transfer data from
producers to their consumers
Value is set using '<<' operator
A task blocks until value has been set by another
task
DF Variable can only be set only one in its
lifetime
Don't have to bother with ordering and
synchronizing the tasks or threads
54. Dataflow
def x = new DataflowVariable()
def y = new DataflowVariable()
def z = new DataflowVariable()
task{z << x.val + y.val}
task{x << 10}
task{y << 5}
println "Result : $z.val"