© Adam L. Davis 2019
Adam L. DavisLearning Groovy 3https://doi.org/10.1007/978-1-4842-5058-7_10

10. Groovy GPars

Adam L. Davis1 
(1)
New York, NY, USA
 

GPars1 is an open source project to bring many concurrency abstractions to Java and/or Groovy. It was bundled in Groovy for a short time and then later pulled out.

It includes parallel map/reduce, Actors, Dataflow, and many other concurrency models. Although any concurrency library made for Java, such as RxJava, Project Reactor, or Akka, can be used with Groovy, GPars was made with Groovy specifically in mind.

Getting Started

To get started you first need to include GPars in your project. For example, in a Gradle build file, add the following to your dependencies block :
compile "org.codehaus.gpars:gpars:1.2.1"
For a maven build, add the following to your dependencies:
<dependency>
    <groupId>org.codehaus.gpars</groupId>
    <artifactId>gpars</artifactId>
    <version>1.2.1</version>
</dependency>

Parallel Map Reduce

In this section we will use a list of students with graduation years and GPAs.
class Student { int graduationYear; double gpa; }
// create a list of students
Collection<Student> students = new ArrayList<>()
You perform parallel map/reduce with the GPars library in the following way:
1   GParsPool.withPool {
2       // a map-reduce functional style
3       def bestGpa = students.parallel
4           .filter{ s -> s.graduationYear==Student.THIS_YEAR }
5           .map{ s -> s.gpa }
6           .max()
7   }

The static method GParsPool.withPool takes in a closure and augments any Collection with several methods (using Groovy’s Category mechanism). The parallel method actually creates a ParallelArray (JSR-1662) from the given Collection and uses it with a thin wrapper around it.3

Actors

The Actor design pattern is a useful pattern for developing concurrent software. In this pattern, each Actor executes in its own thread and manipulates its own data. The data cannot be manipulated by any other thread. Messages are passed (internally by GPars) between the Actors to cause them to change the data. You can also make stateless Actors.

When data can be changed by only one thread at a time, it’s called thread-safe.

 0   @Grab("org.codehaus.gpars:gpars:1.2.1")
 1   import groovyx.gpars.actor.Actor
 2   import groovyx.gpars.actor.DefaultActor
 3
 4   class Dragon extends DefaultActor {
 5       int age
 6
 7       void afterStart() {
 8           age = new Random().nextInt(1000) + 1
 9       }
11       void act() {
12           loop {
13               react { int num ->
14                 if (num > age)
15                 reply 'too old'
16                 else if (num < age)
17                 reply 'too young'
18                 else  {
19                   reply 'you guessed right!'
20                   terminate()
21                 }
22               }
23           }
24       }
25   }
26   // Guesses the age of the Dragon
27   class Guesser extends DefaultActor {
28       String name
29       Actor server
30       int myNum
31
32       void act() {
33           loop {
34             myNum = new Random().nextInt(1000) + 1
35             server.send myNum
36             react {
37               switch (it) {
38                 case 'too old': println "$name: $myNum was too old"; break
39                 case 'too young': println "$name: $myNum was too young"; break
40                 default: println "$name: I won $myNum"; terminate(); break
41               }
42             }
43           }
44         }
45   }
46
47   def  master = new  Dragon().start()
48   def player = new Guesser(name: 'Guesser', server: master).start()
49
50   //this forces main thread to live until both actors stop
51   [master, player]*.join()

Here the Dragon class starts with some random age between 1 and 1000. It then reacts to a given number, replying if the number is too big, too small, or the same as its age. The Guesser class loops, generating a random guess each time through the loop and sending it to the Dragon (referred to as server). The Guesser then reacts to the message from the Dragon and terminates when the correct age was guessed.

The output will be something like the following:
Guesser: 236 was too young
... many other guesses
Guesser: 819 was too old
Guesser: I won 527

More GPars

For more information on other parts of GPars, such as Agents (which are much like Actors with functions as messages), Dataflow (an alternative concurrency model with deterministic behavior), and STM (Software Transactional Memory, which gives developers transactional syntax for dealing with in-memory state), please see GPars’ excellent guide online.4

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset