Actor
Scala 的 Actor 類似於 Java 中的多線程編程。但是不同的是,Scala 的 Actor提供的模型與多線程有所不同。Scala 的 Actor 儘可能地避免鎖和共享狀態,從而避免多線程併發時出現資源爭用的情況,進而提升多線程編程的性能。此外, Scala Actor 的這種模型還可以避免死鎖等一系列傳統多線程編程的問題。
Spark 中使用的分佈式多線程框架,是Akka 。Akka 也實現了類似 Scala Actor的模型,其核心概念同樣也是 Actor。
Actor的創建、啓動和消息收發
Scala 提供了 Actor trait 來讓我們更方便地進行 actor 多線程編程,Actor trait 就類似於 Java 中的 Thread 和 Runnable 一樣,是基礎的多線程基類和接口。我們只要重寫 Actor trait 的 act 方法,即可實現自己的線程執行體,與 Java 中重寫 run 方法類似。
此外,使用 start() 方法啓動 actor;使用 ! 符號向 actor 發送消息;actor 內部使用 receive 和模式匹配接收消息。
import scala.actors.Actor
class HelloActor extends Actor{
def act(){
while(true){
receive{
case name:String => println("Hello," + name)
}
}
}
}
val helloActor = new HelloActor
helloActor.start()
helloActor ! "Li"
收發 case class 類型的消息
Scala 的 Actor 模型與 Java 的多線程模型之間,很大的一個區別就是,Scala Actor 天然支持線程之間的精準通信;即一個 actor 可以給其他 actor 直接發送消息。這個功能是非常強大和方便的。
要給一個 actor 發送消息,需要使用 “actor ! 消息” 的語法。在 Scala 中,通常建議使用樣例類,即 case class 來作爲消息進行發送。然後在 actor 接收消息之後,可以使用 Scala 強大的模式匹配功能來進行不同消息的處理。
case class Login(username:String, password:String)
case class Register(username:String, password:String)
class UserManageActor extends Actor{
def act(){
while(true){
receive{
case Login(username,password) => println("login,username is " + username + ",password is " + password)
case Register(username,password) => println("register,username is " + username + ",password is " + password)
}
}
}
}
val userManageActor = new UserManageActor
userManageActor.start()
userManageActor ! Register("Li","123")
userManageActor ! Login("Li","123")
Actor之間互相收發消息
如果兩個 Actor 之間要互相收發消息,那麼 Scala 的建議是,一個 actor 向另外一個 actor 發送消息時,同時帶上自己的引用;其他 actor 收到自己的消息時,直接通過發送消息的 actor 的引用,即可以給它回覆消息。
case class Message(content:String, sender:Actor)
class LiTelephoneActor extends Actor{
def act(){
while(true){
receive{
case Message(Content,sender) => {
println("Li telephone: " + content);
sender ! "I'm li, pleace call me after 10 minutes."
}
}
}
}
}
class ChyTelephoneActor(val LiTelephoneActor:Actor) extends Actor{
def act(){
LiTelephoneActor ! Message("Hello,Li, I'm Chy", this)
receive{
case response:String => println("Chy telephone: " + response)
}
}
}
同步消息和Future
默認情況下,消息都是異步的;但是如果希望發送的消息是同步的,即對方接受後,一定要給自己返回結果,那麼可以使用 !? 的方式發送消息。
val reply = actor !? message
如果要異步發送一個消息,但是在後續要獲得消息的返回值,那麼可以使用 Future,即 !! 語法。
val future = actor !! message
val reply = future()