scala下使用akka計算pi

Akka 是一個用 Scala 編寫的庫,用於簡化編寫容錯的、高可伸縮性的 Java 和 Scala 的 Actor 模型應用。它已經成功運用在電信行業。系統幾乎不會宕機(高可用性 99.9999999 % 一年只有 31 ms 宕機。

用akka計算pi,計算公式:


這樣,我們把這個公式每連續的elements個分成一段,一共分成message段。

然後開worker個actor同時計算,把結果合併。算出最終結果和耗時。

一:計算某一段的actor

我們需要一個工作actor,用來計算某一段的和,並把結果傳出去。

class Worker extends Actor {

  //計算從start開始,連續elements個的和
  def calculatePiFor(start: Int, elements: Int): Double = {
    var acc = 0.0
    for (i <- start until (start + elements))
      acc += 4.0 * (1 - (i % 2) * 2) / (2 * i + 1)
    acc
  }

  def receive = {
    // sender 用來訪問當前消息的發送者的引用
    case Work(start, elements) => sender ! Result(calculatePiFor(start, elements))
  }
}
二:創建主actor

主actor的工作是把任務分配下去,並且把Worker執行的結果進行收集處理,並且把處理完的最終結果返回給監聽actor

分配任務我們就需要創建一個round-robin的路由器來簡化把任務平均分配給工作者的過程。

 //創建了一個路由器,啓動了workers個Worker
  val workerRouter = context.actorOf(
    Props[Worker].withRouter(RoundRobinRouter(workers)), name = "workerRouter")
對於主actor,會接受兩種消息,一種是計算,一種是收到結果處理。

class Master(workers: Int, messages: Int, elements: Int, listener: ActorRef) extends Actor {

  var pi: Double = 0.0
  var finish: Int = 0
  val startTime: Long = System.currentTimeMillis()
  
  //創建了一個路由器,啓動了workers個Worker
  val workerRouter = context.actorOf(
    Props[Worker].withRouter(RoundRobinRouter(workers)), name = "workerRouter")

  def receive = {

    //收到計算的請求,把計算的任務分配下去
    case Calculate =>
      for (i <- 0 until messages)
        workerRouter ! Work(i * elements, elements)
    //收到計算的結果,把計算的結果加到pi上,並且判斷下發的任務有沒有全部執行完畢
    //如果全部執行完畢,那麼給監聽者發一個消息
    case Result(value) =>
      pi += value
      finish += 1
      if (finish == messages) {

        listener ! PiApproximation(pi, duration = (System.currentTimeMillis - startTime))

        context.stop(self)
      }
  }
}
三:監聽actor

監聽actor比較簡單,收到數據,直接輸出就好

class Listener extends Actor {

  def receive = {

    case PiApproximation(pi, duration) =>
      println("計算結束,結果爲: " + pi + "用時 : " + duration)
  }

}

四:最終結果

package akka.study.base

import akka.actor._
import akka.routing.RoundRobinRouter
import java.util.concurrent.TimeUnit
import java.lang.System._
import java.time.Duration

sealed trait PiMessage
case object Calculate extends PiMessage
case class Work(start: Int, elements: Int) extends PiMessage
case class Result(value: Double) extends PiMessage
case class PiApproximation(pi: Double, duration: Long)

class Worker extends Actor {

  //計算從start開始,連續elements個的和
  def calculatePiFor(start: Int, elements: Int): Double = {
    var acc = 0.0
    for (i <- start until (start + elements))
      acc += 4.0 * (1 - (i % 2) * 2) / (2 * i + 1)
    acc
  }

  def receive = {
    // sender 用來訪問當前消息的發送者的引用
    case Work(start, elements) => sender ! Result(calculatePiFor(start, elements))
  }
}

class Master(workers: Int, messages: Int, elements: Int, listener: ActorRef) extends Actor {

  var pi: Double = 0.0
  var finish: Int = 0
  val startTime: Long = System.currentTimeMillis()
  
  //創建了一個路由器,啓動了workers個Worker
  val workerRouter = context.actorOf(
    Props[Worker].withRouter(RoundRobinRouter(workers)), name = "workerRouter")

  def receive = {

    //收到計算的請求,把計算的任務分配下去
    case Calculate =>
      for (i <- 0 until messages)
        workerRouter ! Work(i * elements, elements)
    //收到計算的結果,把計算的結果加到pi上,並且判斷下發的任務有沒有全部執行完畢
    //如果全部執行完畢,那麼給監聽者發一個消息
    case Result(value) =>
      pi += value
      finish += 1
      if (finish == messages) {

        listener ! PiApproximation(pi, duration = (System.currentTimeMillis - startTime))

        context.stop(self)
      }
  }
}

class Listener extends Actor {

  def receive = {

    case PiApproximation(pi, duration) =>
      println("計算結束,結果爲: " + pi + "用時 : " + duration)
  }

}

object Pi {

  def main(args: Array[String]) {

    def calculate(workers: Int, elements: Int, messages: Int) {

      val system = ActorSystem("PiSystem")

      val listener = system.actorOf(Props[Listener], name = "listener")

      val master = system.actorOf(Props(new Master(
        workers, messages, elements, listener)),
        name = "master")

      master ! Calculate
    }
    
    calculate(6, 10000, 10000)
  }
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章