Scala concurrent programming series --Scala Actor

 

First, the basic introduction

1, the concept of

        Actor Scala in parallel programming enables powerful features, it is based concurrency event model, Scala is the use of a message (message) sending, receiving, to achieve multi-threaded. Scala makes it easier to use multi-threaded application development.

2, the difference between the traditional and the concurrent programming java programming Scala Actor

        For Java, we all know that it is multi-threaded implementation requires a shared resource (variables, objects, etc.) using the synchronized keyword block synchronization code, object lock mutex and so on. Moreover, often a chunk try ... catch statement block plus the wait method, notify method, notifyAll method is very stressful. The reason is that Java is used in most of the state of the object variable resources, sharing of these resources to achieve multi-threaded programming, control the resources to compete with the state of the object is to prevent accidental modification is very important, and the state of the object invariance but also the more difficult to secure. In Scala, we can not change state by copying the resource (i.e. the object, Scala, everything is an object, even a function, a method is also) a copy of the sent message and then based on the Actor, received parallel programming mechanism

3, Actor method execution sequence

1. First call the start () method to start Actor

2. After the call to start () method that act () method will be executed

3. Send a message to the Actor

4, the message transmission mode

! Send asynchronous messages, no return value.

!? Sends synchronization message, wait for the return value.

!! send asynchronous messages, the return value is Future [Any].

Two, Actor combat

1, an example of a

package cn.itcast.actor
//注意导包是scala.actors.Actor
import scala.actors.Actor
object MyActor1 extends Actor{
  //重新act方法
  def act(){
    for(i <- 1 to 10){
      println("actor-1 " + i)
      Thread.sleep(2000)
    }
  }
}
object MyActor2 extends Actor{
  //重新act方法
  def act(){
    for(i <- 1 to 10){
      println("actor-2 " + i)
      Thread.sleep(2000)
    }
  }
}
object ActorTest extends App{
  //启动Actor
  MyActor1.start()
  MyActor2.start()
}

Note: The above are calls start () method singleton two objects, they act () method is executed, the same opening in java two threads, the thread run () method is executed

Note: Both Actor are executed in parallel, act () for loop is executed after completion method actor withdrew from the program

2, an example of two (can continue to receive messages)

class MyActor extends Actor {
  override def act(): Unit = {
    while (true) {
      receive {
        case "start" => {
          println("starting ...")
          Thread.sleep(5000)
          println("started")
        }
        case "stop" => {
          println("stopping ...")
          Thread.sleep(5000)
          println("stopped ...")
        }
      }
    }
  }
}
object MyActor {
  def main(args: Array[String]) {
    val actor = new MyActor
    actor.start()
    actor ! "start"
    actor ! "stop"
    println("消息发送完成!")
  }
}

Description: adding while (true) loop in act () method, can stop receiving messages

Note: sending start messages and stop message is asynchronous, but the process Actor received message is executed in the order of execution of synchronization

3, three examples (REACT embodiment will multiplexed threads, more efficient than the receive)

class YourActor extends Actor {
  override def act(): Unit = {
    loop {//一个内核一个线程,如果一个内核多个线程,线程还是会切换
      react {
        case "start" => {
          println("starting ...")
          Thread.sleep(5000)
          println("started")
        }
        case "stop" => {
          println("stopping ...")
          Thread.sleep(8000)
          println("stopped ...")
        }
      }
    }
  }
}
object YourActor {
  def main(args: Array[String]) {
    val actor = new YourActor
    actor.start()
    actor ! "start"
    actor ! "stop"
    println("消息发送完成!")
  }
}

Description: react if the message processing to be performed repeatedly, react to use the outer loop, while not used

4, four examples (binding message transmission case class)

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)

Third, exercise

        Write a single version of WorldCount with actor concurrent programming, multiple files as input, calculate summary after completing a number of tasks to get the final result

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
      //线程执行完后,返回结果放到Future[Any],即返回结果类型为Future[Any]
      val replay = t.start() !! SubmitTask(f)
      replaySet += replay
    }
    while(replaySet.size > 0){
      val toCumpute = replaySet.filter(_.isSet)
      for(r <- toCumpute){
        val result = r.apply()//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])

Note: We are now learning Scala Actor scala 2.10.x version and previous versions of Actor. In the version in the Scala 2.11.x Akka added thereto, as its default Actor, Actor old version obsolete [unavailable]

Published 107 original articles · won praise 184 · views 210 000 +

Guess you like

Origin blog.csdn.net/qq_22172133/article/details/83749583