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)
  }
}
时间: 2024-10-13 19:55:40

scala下使用akka计算pi的相关文章

scala笔记和akka笔记

非阻塞的程序 应该保障的一些特性 : 等待无关性wait-free:能确保每次的调用在有限的步数之内完成,不管其他调用的步骤有多少.杀掉几个线程 锁无关性lock-free:执行这段程序的某些线程会被延迟,但必须确保至少有一个线程能持续步骤到执行完毕.这一点需防止可能出现的饿死,就是说防止某个线程永远被延迟. 阻碍阻塞无关性obstruction-free:有个时间点,在这个点之后非阻塞方法独立的在有限次步骤内执行完毕 锁无关的程序一定是阻碍无关的,反之不一定. 乐观并行控制法是障碍阻塞无关的,

计算pi的精度+进度条显示

步骤1:安装tqdm 首先,要打开cmd,输入指令,不断找到python文件的路径,知道找到Scripts,然后分别打入pip install pygame和pip install tqdm  如下图 步骤2:输入计算pi的代码(顺带输入一下跟进度条有关的代码): from random import random from math import sqrt from time import clock from tqdm import tqdm import time DARTS=800000

python 下的crc16计算模块 XCRC16

又一次突然遇到用python处理modbus通信而需要crc16校验的问题,当时在百度上没找到,在google上找到了一个外国人开发的python包,结果安装好了之后发现校验的不正确(可能是使用的模式串不一样,xcrc16的模式串为0xa001),后来事情过去了就写了一个包弥补一下,xcrc16 的意思是 extend crc->xcrc ,也是我的第一个开源项目,如果大家使用程序遇到什么情况也麻烦通知我下,我会第一时间进行维护. 介绍: xcrc16 模块是为了解决crc16校验问题而写 目前

android 软键盘在全屏下的布局计算问题

在非全屏模式下,将activity的windowSoftInputMode的属性设置为:adjustResize.同时在View的onSizeChanged(int w, int h, int oldw, int oldh)里可以得到变化后的尺寸,然后根据前后变化的结果来计算屏幕需要移动的距离. 但是在全屏模式下,即使将activity的windowSoftInputMode的属性设置为:adjustResize.在键盘显示时它未将Activity的Screen向上推动,所以你Activity的

概率法计算PI

#include <iostream> using namespace std; //概率计算PI int main() { int inside=0; double val; int i; for ( i=0; i<100000000; i++) { double x = (double)(rand())/RAND_MAX; double y = (double)(rand())/RAND_MAX; if ( (x*x + y*y) <= 1.0 ) { inside++; }

Scala下Play框架学习笔记(Actions,Controllers and Results)

Scala下Play框架的学习是一件辛苦的事情,因为该框架比较新,scala语言也较新,所以中文资料很少,经过同事推荐,去了如下英文网站看资料: https://www.playframework.com/documentation/2.5.x/ScalaHome 虽然我的同事以在云中飞的速度学完了,但对我来说还是任重而道远. Action是什么? 由于Scala和Play有关的API都在play.api下面,所以其实Action的过程是这样的: play.api.mvc.Action(play

使用随机数计算pi值--java实现

1.先上一张图 2.原理分析 上图展示的是,在二维坐标图中,半径为1的圆的1/4, 随机n个点(x坐标在0~1之间,并且y坐标在0~1之间),落在半径为1的圆内部,当点的样本足够多的时候,形成1/4的饼图. 3.代码实现 /** * */ package com.sunny.www.interview; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.Scanner; /** * 使用随机数

用hadoop计算PI值

一.计算PI值的方式与原理 百度一下,计算PI的方法还真不少.但在hadoop examples代码中的注释写的是:是采用 Quasi-Monte Carlo 算法来估算PI的值. 维基百科中对Quasi-Monte Carlo的描述比较理论,好多难懂的公式. 好在google了一把,找到了斯坦福大学网站上的一篇文章:<通过扔飞镖也能得出PI的值?>,文章很短,图文并茂,而且很好理解. 我这里将那篇文章的重要部分截了个图: 对上面的图再稍微解释一下:       1.Figure2是Figur

scala下划线

作为函数的参数 一个匿名的函数传递给一个方法或者函数的时候,scala会尽量推断出参数类型.例如一个完整的匿名函数作为参数可以写为 scala> def compute(f: (Double)=>Double) = f(3) compute: (f: Double => Double)Double //传递一个匿名函数作为compute的参数 scala> compute((x: Double) => 2 * x) res1: Double = 6.0 如果参数x在=>