概念
学习路线
Actor --> Akka --> Spark
Actor:是消息并发模型
scala中的Actor能够实现并行编程的强大功能,它是基于事件模型的并发机制。scala是运用消息(message)的发送、接收来实现多线程的。
使用scala能够更容易地实现多线程应用的开发。
Java并发编程与scala Actor编程的区别
Scala的actor类似于Java中的多线程编程。但是不同的是,scala的Actor提供的模型与多线程有所不同,scala的Actor尽可能地避免锁和共享状态,从而避免多线程并发时出现资源争用的情况,进而提升多线程编程的性能。此外,scala actor的这种模型还可以避免死锁等一系列传统多线程编程的问题。原因就在于Java中多数使用的是可变状态的对象资源,对这些资源进行共享来实现多线程编程的话,控制好资源竞争与防止对象状态被意外修改是非常重要的,而对象状态的不变性也是较难以保证的。而在scala中,我们可以通过复制不可变状态的资源〈即对象,scala中一切都是对象,连函数、方法也是〉的一个副本,再基于Actor的消息发送、接收机制进行并行编程。
Actor 方法执行顺序
- 调用start()方法启动Actor
- 执行act()方法
- 向Actor发送消息
发送消息的方式
4. ! -->发送异步消息,没有返回值
5. !? -->发送同步消息,等待返回值
6. !! -->发送异步消息,返回值是Future[Any]
简单练习
package day05
import scala.actors.Actor
class ActorDemo1 {
}
// 重写act方法
object ActorDemo1 extends Actor{
override def act(): Unit = {
for (i<-1 to 20){
println("actor1:"+i)
Thread.sleep(1000)
}
}
}
object ActorDemo2 extends Actor{
override def act(): Unit = {
for (i<-1 to 20){
println("actor2:"+i)
Thread.sleep(1000)
}
}
}
object ActorTest{
def main(args: Array[String]): Unit = {
// 启动Actor
ActorDemo1.start()
ActorDemo2.start()
}
}
三种消息发送方式的练习
package day05
import scala.actors.{Actor, Future}
/**
* 用Actor实现同步和异步的消息的发送和消息的接收
*/
class ActorDemo3 extends Actor {
override def act(): Unit = {
while (true) {
// 偏函数
receive {
case "start" => println("starting...")
case AsyncMsg(id, msg) => {
println(s"id:$id,AsyncMsg:$msg")
Thread.sleep(2000)
sender ! ReplyMsg(5, "success")
}
case SyncMsg(id, msg) => {
println(s"id:$id,SyncMsg:$msg")
Thread.sleep(2000)
sender ! ReplyMsg(5, "success")
}
}
}
}
}
case class AsyncMsg(id: Int, msg: String)
case class SyncMsg(id: Int, msg: String)
case class ReplyMsg(id: Int, msg: String)
object ActorDemo3 {
def main(args: Array[String]): Unit = {
val actorDemo3: ActorDemo3 = new ActorDemo3
actorDemo3.start()
// // 异步发送消息,没有返回值
// actorDemo3 ! AsyncMsg(1, "Hi~ ,Li")
// println("没有返回值的异步消息发送完成")
//
// // 同步发送消息,线程等待返回值
// val content: Any = actorDemo3 !? SyncMsg(2, "Hi~ ,Wang")
// println("有返回值的同步消息发送完成")
// println(content)
// 异步发送消息,有返回值,返回类型是Future[Any]
val reply: Future[Any] = actorDemo3 !! AsyncMsg(3, "Hi~ ,Zhao")
// Thread.sleep(5)
Thread.sleep(3000)
if (reply.isSet){
val value=reply.apply()
println(value)
}else{
println("None")
}
}
}
实现wordcount
package day05
import scala.actors.{Actor, Future}
import scala.collection.mutable.ListBuffer
import scala.io.Source
/**
* 用Actor并发编程实现WordCount
*/
class ActorWordCount {
}
object ActorWordCount {
def main(args: Array[String]): Unit = {
// 存放接收到的每个文件的结果数据
val replys: ListBuffer[Future[Any]] = new ListBuffer[Future[Any]]
// 存放有值的Future里的数据
val res: ListBuffer[Map[String, Int]] = new ListBuffer[Map[String, Int]]
val files: Array[String]
= Array(
"E:\\test\\a.txt",
"E:\\test\\b.txt",
"E:\\test\\c.txt"
)
for (file <- files) {
// val lines: List[String] = Source.fromFile(file).getLines().toList
// val words: List[String] = lines.flatMap(_.split(" "))
// val res: Map[String, Int] = words.map((_, 1)).groupBy(_._1).mapValues(_.size)
val task = new Task
task.start()
// 接收结果数据,异步发送消息,有返回值
val reply: Future[Any] = task !! SmTask(file)
replys += reply
}
while (replys.size > 0) {
// 过滤每个Future对象,如果None类型的,就过滤掉
val dones: ListBuffer[Future[Any]] = replys.filter(_.isSet)
for (done <- dones) {
res += done.apply().asInstanceOf[Map[String, Int]]
replys -= done
}
}
// flatten 压平,根据key进行分组,对值进行求和
val map = res.flatten.groupBy(_._1).mapValues(_.foldLeft(0)(_ + _._2))
println(map)
}
}
class Task extends Actor {
override def act(): Unit = {
while (true) {
receive({
case SmTask(file) => {
val lines: List[String] = Source.fromFile(file).getLines().toList
val words: List[String] = lines.flatMap(_.split(" "))
val res: Map[String, Int] = words.map((_, 1)).groupBy(_._1).mapValues(_.size)
// 异步发送结果数据,没有返回值
sender ! res
}
})
}
}
}
// 整理成偏函数,然后调用,后期方便修改
case class SmTask(file: String)