注:我们现在学的Scala Actor是scala 2.10.x版本及以前版本的Actor。

Scala在2.11.x版本中将Akka加入其中,作为其默认的Actor,老版本的Actor已经废弃

一、概述

  1.什么是actor

  Scala的Actor类似于Java中的多线程编程。但是不同的是,Scala的Actor提供的模型与多线程有所不同。Scala的Actor尽可能地避免锁和共享状态,从而避免多线程并发时出现资源争用的情况,进而提升多线程编程的性能。此外,Scala Actor的这种模型还可以避免死锁等一系列传统多线程编程的问题。 Spark中使用的分布式多线程框架,是Akka。Akka也实现了类似Scala Actor的模型,其核心概念同样也是Actor

  2.scala与传统Java多线程编程

  

  

  对于Java,我们都知道它的多线程实现需要对共享资源(变量、对象等)使用synchronized 关键字进行代码块同步、对象锁互斥等等。而且,常常一大块的try…catch语句块中加上wait方法、notify方法、notifyAll方法是让人很头疼的。原因就在于Java中多数使用的是可变状态的对象资源,对这些资源进行共享来实现多线程编程的话,控制好资源竞争与防止对象状态被意外修改是非常重要的,而对象状态的不变性也是较难以保证的。

  而在Scala中,我们可以通过复制不可变状态的资源(即对象,Scala中一切都是对象,连函数、方法也是)的一个副本,再基于Actor的消息发送、接收机制进行并行编程。

  3.actor方法执行顺序

    1.首先调用start()方法启动Actor

    2.调用start()方法后其act()方法会被执行

    3.向Actor发送消息

  4.发送消息的方法

    

!

发送异步消息,没有返回值。

!?

发送同步消息,等待返回值。

!!

发送异步消息,返回值是 Future[Any]。

二、Actor实战

  1.快速入门示例

    Scala提供了Actor trait来让我们更方便地进行actor多线程编程,就Actor trait就类似于Java中的Thread和Runnable一样,
  是基础的多线程基类和接口。我们只要重写Actor trait的act方法,即可实现自己的线程执行体,与Java中重写run方法类似。
    此外,使用start()方法启动actor;使用!符号,向actor发送消息;actor内部使用receive和模式匹配接收消息

  1. package com.jiangbei
  2. // 注意这里是2.10版本的Actor所在的包,后续新版本已经废弃,转为Akka
  3. import scala.actors.Actor
  4.  
  5. object ActorTest {
  6. def main(args: Array[String]): Unit = {
  7. println("线程 启动!")
  8. MyActor1.start()
  9. MyActor2.start()
  10. }
  11. }
  12.  
  13. object MyActor1 extends Actor {
  14. override def act(): Unit = {
  15. for (i <- 11 to 19) {
  16. println("actor01---" + i)
  17. Thread.sleep(500)
  18. }
  19. }
  20. }
  21.  
  22. object MyActor2 extends Actor {
  23. override def act(): Unit = {
  24. for (i <- 21 to 29) {
  25. println("actor02---" + i)
  26. Thread.sleep(500)
  27. }
  28. }
  29. }

  说明:上面分别调用了两个单例对象的start()方法,他们的act()方法会被执行,相同与在java中开启了两个线程,线程的run()方法会被执行

  注意:这两个Actor是并行执行的,act()方法中的for循环执行完成后actor程序就退出了

  2.可以不断地接收消息

  1. package com.jiangbei
  2.  
  3. import scala.actors.Actor
  4.  
  5. object ActorTest {
  6. def main(args: Array[String]): Unit = {
  7. println("线程 启动!")
  8. val actor1 = new MyActor1
  9. actor1.start()
  10. // 以下为异步消息,不等待返回
  11. actor1 ! "start"
  12. actor1 ! "stop"
  13. println("消息发送完毕!")
  14. }
  15. }
  16.  
  17. class MyActor1 extends Actor {
  18. override def act(): Unit = {
  19. while (true) { //以下就是偏函数
  20. receive {
  21. case "start" => {
  22. println("启动中...")
  23. Thread.sleep(500)
  24. println("启动完成!")
  25. }
  26. case "stop" => {
  27. println("停止中...")
  28. Thread.sleep(500)
  29. println("停止完成!")
  30. }
  31. }
  32. }
  33. }
  34. }

  结果:

  1. 线程 启动!
  2. 消息发送完毕!
  3. 启动中...
  4. 启动完成!
  5. 停止中...
  6. 停止完成!

  3.react方式会复用线程,比receive更高效

  1. package com.jiangbei
  2.  
  3. import scala.actors.Actor
  4.  
  5. object ActorTest {
  6. def main(args: Array[String]): Unit = {
  7. println("线程 启动!")
  8. val actor1 = new MyActor1
  9. actor1.start()
  10. // 以下为异步消息,不等待返回
  11. actor1 ! "start"
  12. actor1 ! "stop"
  13. println("消息发送完毕!")
  14. }
  15. }
  16.  
  17. class MyActor1 extends Actor {
  18. override def act(): Unit = {
  19. loop {
  20. react {
  21. case "start" => {
  22. println("starting ...")
  23. Thread.sleep(1000)
  24. println("started")
  25. }
  26. case "stop" => {
  27. println("stopping ...")
  28. Thread.sleep(1000)
  29. println("stopped ...")
  30. }
  31. }
  32. }
  33. }
  34. }

  4.结合case class发送消息

  1. package cn.itcast.actor
  2. import scala.actors.Actor
  3.  
  4. class AppleActor extends Actor {
  5.  
  6. def act(): Unit = {
  7. while (true) {
  8. receive {
  9. case "start" => println("starting ...")
  10. case SyncMsg(id, msg) => {
  11. println(id + ",sync " + msg)
  12. Thread.sleep(5000)
  13. sender ! ReplyMsg(3,"finished")
  14. }
  15. case AsyncMsg(id, msg) => {
  16. println(id + ",async " + msg)
  17. Thread.sleep(5000)
  18. }
  19. }
  20. }
  21. }
  22. }
  23.  
  24. object AppleActor {
  25. def main(args: Array[String]) {
  26. val a = new AppleActor
  27. a.start()
  28. //异步消息
  29. a ! AsyncMsg(1, "hello actor")
  30. println("异步消息发送完成")
  31. //同步消息
  32. //val content = a.!?(1000, SyncMsg(2, "hello actor"))
  33. //println(content)
  34. val reply = a !! SyncMsg(2, "hello actor")
  35. println(reply.isSet)
  36. //println("123")
  37. val c = reply.apply()
  38. println(reply.isSet)
  39. println(c)
  40. }
  41. }
  42. case class SyncMsg(id : Int, msg: String)
  43. case class AsyncMsg(id : Int, msg: String)
  44. case class ReplyMsg(id : Int, msg: String)

  5.练习:actor版wordCount

  1. package cn.itcast.actor
  2.  
  3. import java.io.File
  4.  
  5. import scala.actors.{Actor, Future}
  6. import scala.collection.mutable
  7. import scala.io.Source
  8.  
  9. /**
  10. * Created by ZX on 2016/4/4.
  11. */
  12. class Task extends Actor {
  13.  
  14. override def act(): Unit = {
  15. loop {
  16. react {
  17. case SubmitTask(fileName) => {
  18. val contents = Source.fromFile(new File(fileName)).mkString
  19. val arr = contents.split("\r\n")
  20. val result = arr.flatMap(_.split(" ")).map((_, 1)).groupBy(_._1).mapValues(_.length)
  21. //val result = arr.flatMap(_.split(" ")).map((_, 1)).groupBy(_._1).mapValues(_.foldLeft(0)(_ + _._2))
  22. sender ! ResultTask(result)
  23. }
  24. case StopTask => {
  25. exit()
  26. }
  27. }
  28. }
  29. }
  30. }
  31.  
  32. object WorkCount {
  33. def main(args: Array[String]) {
  34. val files = Array("c://words.txt", "c://words.log")
  35.  
  36. val replaySet = new mutable.HashSet[Future[Any]]
  37. val resultList = new mutable.ListBuffer[ResultTask]
  38.  
  39. for(f <- files) {
  40. val t = new Task
  41. val replay = t.start() !! SubmitTask(f)
  42. replaySet += replay
  43. }
  44.  
  45. while(replaySet.size > 0){
  46. val toCumpute = replaySet.filter(_.isSet)
  47. for(r <- toCumpute){
  48. val result = r.apply()
  49. resultList += result.asInstanceOf[ResultTask]
  50. replaySet.remove(r)
  51. }
  52. Thread.sleep(100)
  53. }
  54. val finalResult = resultList.map(_.result).flatten.groupBy(_._1).mapValues(x => x.foldLeft(0)(_ + _._2))
  55. println(finalResult)
  56. }
  57. }
  58.  
  59. case class SubmitTask(fileName: String)
  60. case object StopTask
  61. case class ResultTask(result: Map[String, Int])

大数据入门第二十一天——scala入门(一)并发编程Actor的更多相关文章

  1. 大数据入门第二十一天——scala入门(二)并发编程Akka

    一.概述 1.什么是akka Akka基于Actor模型,提供了一个用于构建可扩展的(Scalable).弹性的(Resilient).快速响应的(Responsive)应用程序的平台. 更多入门的基 ...

  2. 大数据入门第二十天——scala入门(一)入门与配置

    一.概述 1.什么是scala  Scala是一种多范式的编程语言,其设计的初衷是要集成面向对象编程和函数式编程的各种特性.Scala运行于Java平台(Java虚拟机),并兼容现有的Java程序. ...

  3. 大数据入门第二十天——scala入门(二)scala基础01

    一.基础语法 1.变量类型 // 上表中列出的数据类型都是对象,也就是说scala没有java中的原生类型.在scala是可以对数字等基础类型调用方法的. 2.变量声明——能用val的尽量使用val! ...

  4. 大数据入门第二十天——scala入门(二)scala基础02

    一. 类.对象.继承.特质 1.类 Scala的类与Java.C++的类比起来更简洁 定义: package com.jiangbei //在Scala中,类并不用声明为public. //Scala ...

  5. 大数据入门第十二天——sqoop入门

    一.概述 1.sqoop是什么 从其官网:http://sqoop.apache.org/ Apache Sqoop(TM) is a tool designed for efficiently tr ...

  6. 大数据入门第十二天——azkaban入门

    一.概述 1.azkaban是什么 通过官方文档:https://azkaban.github.io/ Azkaban is a batch workflow job scheduler create ...

  7. 大数据入门第十二天——flume入门

    一.概述 1.什么是flume 官网的介绍:http://flume.apache.org/ Flume is a distributed, reliable, and available servi ...

  8. 大数据入门第十九天——推荐系统与mahout(一)入门与概述

    一.推荐系统概述 为了解决信息过载和用户无明确需求的问题,找到用户感兴趣的物品,才有了个性化推荐系统.其实,解决信息过载的问题,代表性的解决方案是分类目录和搜索引擎,如hao123,电商首页的分类目录 ...

  9. 大数据入门第十七天——storm上游数据源 之kafka详解(一)入门与集群安装

    一.概述 1.kafka是什么 根据标题可以有个概念:kafka是storm的上游数据源之一,也是一对经典的组合,就像郭德纲和于谦 根据官网:http://kafka.apache.org/intro ...

随机推荐

  1. MUI - IOS系统,相册选择照片后,点击确定按钮无反应

    MUI框架下使用 plus.gallery.pick 时,选择好照片之后,点击确定按钮无反应(既没报错,也没正确执行成功或失败后的回调方法).这是在做测试时,其中有两台苹果机上出现的bug.做了调试也 ...

  2. Sqoop安装与应用过程

    1.  参考说明 参考文档: http://sqoop.apache.org/ http://sqoop.apache.org/docs/1.99.7/admin/Installation.html ...

  3. 在Silverlight中动态绑定页面报表(PageReport)的数据源

    ActiveReports 7中引入了一种新的报表模型——PageReport(页面布局报表),这种报表模型又细分了两种具体显示形式: o    固定页面布局报表模型(FPL)是ActiveRepor ...

  4. 大数据【一】集群配置及ssh免密认证

    八月迷情,这个月会对大数据进行一个快速的了解学习. 一.所需工具简介 首先我是在大数据实验一体机上进行集群管理学习,管理五台实验机,分别为master,slave1,slave2,slave3,cli ...

  5. 如何用 Python 实现 Web 抓取?

    [编者按]本文作者为 Blog Bowl 联合创始人 Shaumik Daityari,主要介绍 Web 抓取技术的基本实现原理和方法.文章系国内 ITOM 管理平台 OneAPM 编译呈现,以下为正 ...

  6. linux 下查看外网ip

    1. curl ipinfo.io ~/codes/qt_codes/qt-5.4.1-build$ curl ipinfo.io{  "ip": "114.241.21 ...

  7. PowerShell发送邮件(587)

    #定义邮件服务器 $smtpServer = "mail.xx.com" $smtpUser = "sender" $smtpPassword = " ...

  8. Linux 补丁生成与使用

    我们在升级Linux 内核的时候,难免会接触到补丁的知识.下面对如何生成补丁和如何打补丁作讲解. 生成补丁: 制作 hello.c 和 hello_new.c 两个文件如如下所示. ➜ diff ls ...

  9. python基础学习2

    一.算数运算符 +加法,-减法,*乘法,/除法,//地板除,%求余,**幂运算. 二.逻辑运算符 非not.且and.或or.优先级依次为not,and,or. 三.print()end结尾 prin ...

  10. 清理 Xcode 10

    1,清理 ~/Library/Developer/CoreSimulator/Devices说明:该目录存放当前的所有模拟器,每个标识符代表一台机器,清理掉避免存在旧版本的模拟器缓存 执行: 关闭模拟 ...