9.1 Performance - Reference Documentation
Authors: The Whole GPars Gang
Version: 1.0-SNAPSHOT
9.1 Performance
Your code in Groovy can be just as fast as code written in Java, Scala or any other programing language. This should not be surprising, since GPars is technically a solid tasty Java-made cake with a Groovy DSL cream on it.Unlike in Java, however, with GPars, as well as with other DSL-friendly languages, you are very likely to experience a useful kind of code speed-up for free, a speed-up coming from a better and cleaner design of your application. Coding with a concurrency DSL will give you smaller code-base with code using the concurrency primitives as language constructs. So it is much easier to build robust concurrent applications, identify potential bottle-necks or errors and eliminate them.While this whole User Guide is describing how to use Groovy and GPars to create beautiful and robust concurrent code, let's use this chapter to highlight a few places, where some code tuning or minor design compromises could give you interesting performance gains.Parallel Collections
Methods for parallel collection processing, like eachParallel() , collectParallel() and such use Parallel Array , an efficient tree-like data structure behind the scenes. This data structure has to be built from the original collection each time you call any of the parallel collection methods. Thus when chaining parallel method calls you might consider using the map/reduce API instead or resort to using the ParallelArray API directly, to avoid the Parallel Array creation overhead.GParsPool.withPool {
people.findAllParallel{it.isMale()}.collectParallel{it.name}.any{it == 'Joe'}
people.parallel.filter{it.isMale()}.map{it.name}.filter{it == 'Joe'}.size() > 0
people.parallelArray.withFilter({it.isMale()} as Predicate).withMapping({it.name} as Mapper).any{it == 'Joe'} != null
}
GParsPool.withPool(50) { … }
Actors
GPars actors are fast. DynamicDispatchActors and ReactiveActors are about twice as fast as the DefaultActors , since they don't have to maintain an implicit state between subsequent message arrivals. The DefaultActors are in fact on par in performance with actors in Scala , which you can hardly hear of as being slow.If top performance is what you're looking for, a good start is to identify the following patterns in your actor code:actor { loop { react {msg -> switch(msg) { case String:… case Integer:… } } } }
messageHandler { when{String msg -> ...} when{Integer msg -> ...} }
class MyHandler extends DynamicDispatchActor { public void handleMessage(String msg) { … } public void handleMessage(Integer msg) { … } }
Pool adjustment
GPars allows you to group actors around thread pools, giving you the freedom to organize actors any way you like. It is always worthwhile to experiment with the actor pool size and type. FJPool usually gives better characteristics that DefaultPool , but seems to be more sensitive to the number of threads in the pool. Sometimes using a ResizeablePool or ResizeableFJPool could help performance by automatic eliminating unneeded threads.def attackerGroup = new DefaultPGroup(new ResizeableFJPool(10)) def defenderGroup = new DefaultPGroup(new DefaultPool(5))def attacker = attackerGroup.actor {...} def defender = defenderGroup.messageHandler {...} ...