《快学Scala》第20章部分习题参考解答(Actor)

来源:互联网 发布:宝宝照片创意软件 编辑:程序博客网 时间:2024/06/06 22:25

注:本文所有的代码使用的使Akka的Actor框架,而没有使用Scala原生的Actor框架(deprecated)。

本文只做了前两题,actor编程还是很清晰的,我的框架可能不是最合理的,feel free to put your architect.


第一题

import CoordinatorActor.{CalRequest, CalRespond, StartCal}import akka.actor.{Actor, ActorSystem, Props}import scala.util.Randomobject CoordinatorActor{  def props(arr: Array[Int], n: Int): Props = Props(new CoordinatorActor(arr, n))  case object StartCal  final case class CalRequest(arr: Array[Int], spos: Int, epos: Int)  final case class CalRespond(ans: Long)}class CoordinatorActor(arr: Array[Int], n: Int) extends Actor{  val cal_cnt = 4  val interval = n / cal_cnt  var sum:Long = 0l  var respondCnt = 0  var tstamp1: Long = _  override def receive: Receive = {    case StartCal =>      tstamp1 = System.currentTimeMillis()      var last = 1      for(i <- 1 to (cal_cnt - 1)){        val calActor = context.actorOf(Props[CalActor], s"cal-$i")        calActor ! CalRequest(arr, last, last + interval)        last += (interval + 1)      }      val lastActor = context.actorOf(Props[CalActor], s"cal-$cal_cnt")      lastActor ! CalRequest(arr, last, n)    case CalRespond(partSum) =>      sum += partSum      respondCnt += 1      if(respondCnt == cal_cnt){        println(s"[Actor] total: $sum, average: ${sum / n}")        val tstamp2 = System.currentTimeMillis()        println(s"[Actor] cost time: ${tstamp2 - tstamp1}ms")        context.stop(self)      }  }}class CalActor extends Actor{  import CoordinatorActor._  override def receive: Receive = {    case CalRequest(arr, spos, epos) =>      var sum: Long = 0l      for(i <- spos to epos) sum += arr(i)      sender() ! CalRespond(sum)  }}object p1 extends App {  val n = 10000000  val rand = Random  val arr = new Array[Int](n + 10)  for(i <- 1 to n) arr(i) = rand.nextInt(100)  var sum1: Long = 0l  val tstamp1 = System.currentTimeMillis()  for(i <- 1 to n) sum1 += arr(i)  println(s"total: $sum1, average: ${sum1 / n}")  val tstamp2 = System.currentTimeMillis()  println(s"cost time: ${tstamp2 - tstamp1}ms")  val system = ActorSystem("average-cal")  val coordinatorActor = system.actorOf(CoordinatorActor.props(arr, n), "cal-coordinator")  coordinatorActor ! StartCal}

CalActor:执行计算任务

CoordinatorActor:执行调度管理任务,创建CalActor,执行结果统计。

执行结果:

n = 10000000

total: 495159047, average: 49cost time: 95ms[Actor] total: 495159047, average: 49[Actor] cost time: 51ms[INFO] [07/21/2017 16:51:27.273] [Thread-0] [CoordinatedShutdown(akka://average-cal)] Starting coordinated shutdown from JVM shutdown hookProcess finished with exit code 130 (interrupted by signal 2: SIGINT)

第二题

import java.awt.image.BufferedImageimport java.io.{File}import CoActor.{OpRespond, Start}import OperActor.StartOpimport akka.actor.{Actor, ActorLogging, ActorSystem, Props}// 执行者:执行像素操作object OperActor{  def props(img: BufferedImage, spos: Int, epos: Int, width: Int): Props = Props(new OperActor(img, spos, epos, width))  // 开始操作指令  case object StartOp}class OperActor(img: BufferedImage, spos: Int, epos: Int, width: Int) extends Actor with ActorLogging{  override def receive: Receive = {    case StartOp =>      log.info(s"start operation between $spos and $epos")      for(i <- spos to epos){        for(j <- 0 until width) {          val ori = img.getRGB(j, i)          img.setRGB(j, i, ~ori)        }      }      // 向调度者报告完成      sender() ! OpRespond      log.info(s"end operation between $spos and $epos")  }}// 调度者:对执行者进行调度object CoActor{  def props(img: BufferedImage) : Props = Props(new CoActor((img)))  // 开始调度指令  case object Start  // 完成报告指令  case object OpRespond}class CoActor(img: BufferedImage) extends Actor with ActorLogging {  val height = img.getHeight()  val width = img.getWidth()  val actor_cnt = 5  val interval = height / actor_cnt  var response_cnt = 0  override def receive: Receive = {    case Start =>      log.info("start operation")      var last = 0      for(i <- 1 to (actor_cnt - 1)) {        val opActor = context.actorOf(OperActor.props(img, last, last + interval, width))        last += (interval + 1)        opActor ! StartOp      }      // 开始一个操作者      val lastActor = context.actorOf(OperActor.props(img, last, height - 1, width))      lastActor ! StartOp    case OpRespond =>      response_cnt += 1      // 所有操作者全部完成任务,结束执行      if(response_cnt == actor_cnt){        log.info("end operation")        val outFile = new File("resource/newImage.jpg")        javax.imageio.ImageIO.write(img, "jpg", outFile)        context.stop(self)      }  }}object p2 extends App {//  println(System.getProperty("user.dir"))  val image: BufferedImage = javax.imageio.ImageIO.read(new File("resource/image.jpg"))  val system = ActorSystem("image-op")  // 开始一个调度者  val coActor = system.actorOf(CoActor.props(image), "coordinator")  coActor ! Start}