1. 程式人生 > >Scala系列學習七 Actor

Scala系列學習七 Actor

Scala中的Actor能夠實現並行程式設計的強大功能,它是基於事件模型的併發機制,Scala是運用訊息(message)的傳送、接收來實現多執行緒的。使用Scala能夠更容易地實現多執行緒應用的開發。

1.首先呼叫start()方法啟動Actor 2.呼叫start()方法後其act()方法會被執行 3.向Actor傳送訊息

!

傳送非同步訊息,沒有返回值。

!?

傳送同步訊息,等待返回值。

!!

傳送非同步訊息,返回值是 Future[Any]。

1、初始Actor

object ActorDemo extends Actor {
  /**
    * Scala中的Actor能夠實現並行程式設計的強大功能,
    * 它是基於事件模型的併發機制,Scala是運用訊息(message)的傳送、接收來實現多執行緒的。
    * 使用Scala能夠更容易地實現多執行緒應用的開發。
    */
  override def act(): Unit = {
    for (i <- 1 to 10) {
      println("actor-1" + i)
      Thread.sleep(1000)
    }
  }
}

object ActorDemo2 extends Actor {
  override def act(): Unit = {
    for (i <- 11 to 22) {
      println("actor-2" + i)
      Thread.sleep(1000)
    }
  }
}

object ActorRun1 extends App {
  //呼叫start來進行啟動兩個執行緒,與在java中的run方法是一樣的,這兩個執行緒會並行執行,act()方法中的for迴圈執行完成後actor程式就退出了
  ActorDemo.start()
  ActorDemo2.start()
}

2、繼承Actor類

//使用類進行多執行緒
class ActorDemo3 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 ActorRun2 extends App {
  /**
    * 使用while (true) 迴圈,不停的接收訊息
    * 傳送start訊息和stop的訊息是非同步的,
    * Actor接收到訊息執行的過程是同步的按順序執行
    */
  private val actor = new ActorDemo3
  actor.start()
  actor ! "start"
  actor ! "stop"
  println("訊息傳送結束")

}

3、使用react複用執行緒


//使用react來進行執行緒複用,效率相較於recive要高
class ActorDemo4 extends Actor {
  override def act(): Unit = {
    loop {
      //不在使用while,而是使用loop
      react {
        case "start" => {
          println("starting")
          Thread.sleep(5000)
          println("Started")
        }
        case "stop" => {
          println("stopping ...")
          Thread.sleep(5000)
          println("stopped ...")
        }
      }
    }
  }
}

object ActorRun4 extends App {
  private val actor = new ActorDemo4
  actor.start()
  actor ! "start"
  actor ! "stop"
  println("訊息傳送結束")
}

4、使用case class


//使用case class 來進行訊息的傳送
case class SyncMsg(id: Int, msg: String)

case class AsyncMsg(id: Int, msg: String)

case class ReplyMsg(id: Int, msg: String)

class ActorDemo5 extends Actor {
  override def act(): Unit = {
    loop {
      react {
        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)

        }
      }
    }
  }
}

5、非同步同步訊息傳送


object ActorRun5 extends App {
  private val actor = new ActorDemo5
  actor.start()
  //非同步訊息
  actor ! AsyncMsg(1, "hello actor")
  println("非同步訊息傳送完成")
  //同步訊息
  // 預設情況下,訊息都是非同步的;但是如果希望傳送的訊息是同步的,即對方接受後,一定要給自己返回結果,那麼可以使用!?的方式傳送訊息。即val reply = actor !? message。
  //val content = a.!?(1000, SyncMsg(2, "hello actor"))
  //println(content)
  //如果要非同步傳送一個訊息,但是在後續要獲得訊息的返回值,那麼可以使用Future。即!!語法。val future = actor !! message。val reply = future()。
  val reply = actor !! SyncMsg(2, "hello actor")
  println(reply.isSet)
  //println("123")
  val c = reply.apply()
  println(reply.isSet)
  println(c)

}