注:我们现在学的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和模式匹配接收消息

package com.jiangbei
// 注意这里是2.10版本的Actor所在的包,后续新版本已经废弃,转为Akka
import scala.actors.Actor object ActorTest {
def main(args: Array[String]): Unit = {
println("线程 启动!")
MyActor1.start()
MyActor2.start()
}
} object MyActor1 extends Actor {
override def act(): Unit = {
for (i <- 11 to 19) {
println("actor01---" + i)
Thread.sleep(500)
}
}
} object MyActor2 extends Actor {
override def act(): Unit = {
for (i <- 21 to 29) {
println("actor02---" + i)
Thread.sleep(500)
}
}
}

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

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

  2.可以不断地接收消息

package com.jiangbei

import scala.actors.Actor

object ActorTest {
def main(args: Array[String]): Unit = {
println("线程 启动!")
val actor1 = new MyActor1
actor1.start()
// 以下为异步消息,不等待返回
actor1 ! "start"
actor1 ! "stop"
println("消息发送完毕!")
}
} class MyActor1 extends Actor {
override def act(): Unit = {
while (true) { //以下就是偏函数
receive {
case "start" => {
println("启动中...")
Thread.sleep(500)
println("启动完成!")
}
case "stop" => {
println("停止中...")
Thread.sleep(500)
println("停止完成!")
}
}
}
}
}

  结果:

线程 启动!
消息发送完毕!
启动中...
启动完成!
停止中...
停止完成!

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

package com.jiangbei

import scala.actors.Actor

object ActorTest {
def main(args: Array[String]): Unit = {
println("线程 启动!")
val actor1 = new MyActor1
actor1.start()
// 以下为异步消息,不等待返回
actor1 ! "start"
actor1 ! "stop"
println("消息发送完毕!")
}
} class MyActor1 extends Actor {
override def act(): Unit = {
loop {
react {
case "start" => {
println("starting ...")
Thread.sleep(1000)
println("started")
}
case "stop" => {
println("stopping ...")
Thread.sleep(1000)
println("stopped ...")
}
}
}
}
}

  4.结合case class发送消息

package cn.itcast.actor
import scala.actors.Actor class AppleActor extends Actor { def act(): Unit = {
while (true) {
receive {
case "start" => println("starting ...")
case SyncMsg(id, msg) => {
println(id + ",sync " + msg)
Thread.sleep(5000)
sender ! ReplyMsg(3,"finished")
}
case AsyncMsg(id, msg) => {
println(id + ",async " + msg)
Thread.sleep(5000)
}
}
}
}
} object AppleActor {
def main(args: Array[String]) {
val a = new AppleActor
a.start()
//异步消息
a ! AsyncMsg(1, "hello actor")
println("异步消息发送完成")
//同步消息
//val content = a.!?(1000, SyncMsg(2, "hello actor"))
//println(content)
val reply = a !! SyncMsg(2, "hello actor")
println(reply.isSet)
//println("123")
val c = reply.apply()
println(reply.isSet)
println(c)
}
}
case class SyncMsg(id : Int, msg: String)
case class AsyncMsg(id : Int, msg: String)
case class ReplyMsg(id : Int, msg: String)

  5.练习:actor版wordCount

package cn.itcast.actor

import java.io.File

import scala.actors.{Actor, Future}
import scala.collection.mutable
import scala.io.Source /**
* Created by ZX on 2016/4/4.
*/
class Task extends Actor { override def act(): Unit = {
loop {
react {
case SubmitTask(fileName) => {
val contents = Source.fromFile(new File(fileName)).mkString
val arr = contents.split("\r\n")
val result = arr.flatMap(_.split(" ")).map((_, 1)).groupBy(_._1).mapValues(_.length)
//val result = arr.flatMap(_.split(" ")).map((_, 1)).groupBy(_._1).mapValues(_.foldLeft(0)(_ + _._2))
sender ! ResultTask(result)
}
case StopTask => {
exit()
}
}
}
}
} object WorkCount {
def main(args: Array[String]) {
val files = Array("c://words.txt", "c://words.log") val replaySet = new mutable.HashSet[Future[Any]]
val resultList = new mutable.ListBuffer[ResultTask] for(f <- files) {
val t = new Task
val replay = t.start() !! SubmitTask(f)
replaySet += replay
} while(replaySet.size > 0){
val toCumpute = replaySet.filter(_.isSet)
for(r <- toCumpute){
val result = r.apply()
resultList += result.asInstanceOf[ResultTask]
replaySet.remove(r)
}
Thread.sleep(100)
}
val finalResult = resultList.map(_.result).flatten.groupBy(_._1).mapValues(x => x.foldLeft(0)(_ + _._2))
println(finalResult)
}
} case class SubmitTask(fileName: String)
case object StopTask
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. android 点击数字跳转到电话界面

    实现方式两种: 1,在xml文件下很简单的实现 只需要在textview属性中加入android:autoLink="phone".  <TextView           ...

  2. 解决跨域问题之anywhere

    anywhere搭建服务,ionic PC端和手机端可以通过网址来查看网页效果.解决跨域问题 大家都知道编写完HTML代码后,可以直接在pc端的浏览器查看,但现在手机端越来越广泛了,想跟在pc端查看网 ...

  3. HTML中meta标签作用及属性总结

    在前端开发中编写html静态网页模板时,head标签内总是会带上许多meta标签,大多数时候并不十分了解这些标签的具体作用,只是别人写了我们也写上吧! 今天小编特意查询了一下关于网页中meta标签的作 ...

  4. 使用MonkeyTest对Android客户端进行压力测试

    目录 monkey命令简介 monkey命令参数说明 自动化实例 如何通过日志定位问题   1.monkey命令简介 Monkey是Android中的一个命令行工具,可以运行在模拟器里或实际设备中.它 ...

  5. 如何使用 Packer 在 Azure 中创建 Windows 虚拟机映像

    Azure 中的每个虚拟机 (VM) 都是基于定义 Windows 分发和操作系统版本的映像创建的. 映像可以包括预安装的应用程序和配置. Azure 应用商店为最常见的操作系统和应用程序环境提供了许 ...

  6. SQL Server 子查询错误:No column name was specified for column 2 of 'a' error (转载)

    问: I have a MySQL query and I ran it working fine but same query showing error in SQL Server. SQL Se ...

  7. SQL删除多列语句

    最近在写SQL过程中发现需要对一张表结构作调整(此处是SQL Server),其中需要删除多列,由于之前都是一条SQL语句删除一列,于是猜想是否可以一条语句同时删除多列,如果可以,怎么写法? 第一次猜 ...

  8. md5sum 和 sha256sum用于 验证软件完整性

    md5sum 和 sha256sum 都用来用来校验软件安装包的完整性,本次我们将讲解如何使用两个命令进行软件安装包的校验: sha 是什么?        sha 为 安全散列算法(英语:Secur ...

  9. 转战JS(1) 初探与变量类型、运算符、常用函数与转换

    转战JS(1)初探与变量类型.运算符.常用函数与转换 做为一名.NET后台开发人员,正考滤向Web前端开发转型,之前也写过一代前端代码,可是当再回头看JS,并有转向它的意愿的时候,突然发现:原来JS不 ...

  10. C++类中的特殊成员函数-------复制构造函数

    在C++中存在一个特殊函数,他就是复制构造函数,假如我们有类A,如果有A a;A b=a;   在这种情况下利用A类变量a来给同是A类变量的b来赋值,这个时候类会使用复制构造函数,如果我们不显式声明复 ...