© Adam L. Davis 2016

Adam L. Davis, Learning Groovy, 10.1007/978-1-4842-2117-4_10

10. Groovy GPars

Adam L. Davis

(1)New York, USA

GPars began as a separate project bringing many concurrency abstractions to Groovy, but was bundled in Groovy 1.8 and beyond.

It includes parallel map/reduce , Actors, and many other concurrency models.

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

You perform parallel map/reduce with the GPars library in the following way:

1   GParsPool.withPool {
2       // a map-reduce functional style (students is a Collection)
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-166) from the given Collection and uses it with a thin wrapper around it.1

Actors

The Actor design patternis 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 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.

 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.

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

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