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)
}
}