Beispiel: parallele Primzahlberechnung


... [ Seminar Programmiersprachen und -Systeme ] ... [ Inhaltsverzeichnis ] ... [ saubere Actor Programmierung ] ...
In diesem Beispiel werden Actors genutzt um auf einfache Weise Primzahlen in einem Intervall zu zählen. Die Anzahl der zu nutzenden Actors kann beim Programmaufruf frei bestimmt werden. Das Beispiel stammt aus der Vorlesung von Prof. Schmidt und wurde in der Vorlesung OOP in Java implementiert. Zu finden ist es hier (countPrimes).
Eine komplette Version des Programms ist weiter unten zu finden.

Nötige imports und einige case classes, die in dem Programm genutzt werden:

import scala.actors.Actor._
import scala.actors.Actor

case class Start(von : Long, bis : Long, max : Long)
case class Work()


Der Arbeitsactor, der die Primzahlen innerhalb eines Intervalls zählen soll:

class PrimeAct(von : Long, bis : Long) extends Actor {
  def isPrime(n:Long) : Boolean = {
    var i : Long = 2
    if (n <= 1)
      false
    else {
      while ( n % i != 0 && i * i <= n)
        i += 1

      i * i > n
    }
  }

  def count(von : Long, bis : Long) : Long = {
    var anz : Long = 0
    var i : Long = von
    while (i <= bis){
      if (isPrime(i))
        anz += 1
        i += 1
    }
    anz
  }

  def act() {
    react {
      case work : Work =>
        sender ! count(von,bis)

    }
  }
}


Der Koordinator, der die Arbeit verteilt und die Zwischenergebnisse zusammenzählt:

class Coordinate extends Actor {
  var done : Boolean = false
  var actCount : Int = 0
  var count : Long = 0

  def splitWork(von : Long, bis : Long, max : Long) {
    if (bis - von <= max) {
      val counter = new PrimeAct(von,bis).start()
      counter ! Work()
      actCount += 1
    }
    else {
      val counter = new PrimeAct(von, von + max - 1).start()
      counter ! Work()
      actCount += 1
      splitWork(von + max, bis, max)
    }
  }


  def act() {
    while(!done) {
      receive {
        case start : Start =>
          splitWork(start.von, start.bis, start.max)
          println("Es werden " + actCount + " Actors zur Berechnung verwendet.")
        case msg : Long =>
          count += msg
          actCount -= 1
          done = actCount == 0
      }
    }
    println("Anzahl Primzahlen: " + count)
    exit()
  }
}


Die main Methode:

def main(args : Array[String]){

  val coord = new Coordinate().start()
  try {
    coord ! Start(args(0).toLong,args(1).toLong,args(2).toLong);
  }
  catch {
    case ex =>
      println("Falsche Parameter. Nehme Standardwerte (1, 1000, 500).")
      coord ! new Start(1,1000,500);
  }
}

Das Beispielprogramm


Hinweis an dieser Stelle: Wenn in Scala ein Multithreading- bzw. Actorprogramm wie hier geschrieben wird, muss die main Methode explizit definiert werden, damit der Scala Compiler in der Lage ist den Code zu optimieren. Es wird also davon abgeraten das Hauptprogramm durch Beerbung von Application zu erstellen.

Zum Schluss noch ein paar mögliche Programmaufrufe, die den Geschwindigkeitsvorteil bei Nutzung von mehr als einem Actor demonstrieren. Das Programm wird dann ausgeben wie viele Actors benutzt wurden. Da die Zeiten sehr stark von dem ausführenden System abhängen, werden an dieser Stelle keine Zeiten angegeben.

scala primes 1 2000000 2000000 //Die Primzahlen innerhalb der ersten 2 000 000 Zahlen werden gezählt mit einem Actor
scala primes 1 2000000 1000000 //Die Primzahlen innerhalb der ersten 2 000 000 Zahlen werden gezählt mit zwei Actors
scala primes 1 2000000 200000  //Die Primzahlen innerhalb der ersten 2 000 000 Zahlen werden gezählt mit zehn Actors



... [ Seminar Programmiersprachen und -Systeme ] ... [ Inhaltsverzeichnis ] ... [ saubere Actor Programmierung ] ...