最近研究了一些scala併發的知識,總結一下。
一.簡介
即時響應性是一項決定任何應用程序成敗的關鍵因素。有兩種方式來提高即時響應性:1.多線程,並行運行多個任務。2.有策略的計算,惰性運行任務。
二.惰性求值
1.短路控制,scala不會向前看,所以用到lazy。
注意:多個變量綁定,後續調用,順序不可預知。
2.惰性集合,創建臨時視圖,調用的時候立即求值。
3.無限流轉換有限流
有限序列
無限流-》Stream
三.並行集合
順序集合
順序集合上的方法行爲:它們爲它們的集合中的每個元素順序地執行它們的操作。
並行集合
,Scala 都擁有其並行版本。①例如,ParArray 是Array 對應的並行版本,同樣的,ParHashMap、ParHashSet 和ParVector 分別對應於HashMap、HashSet 和Vector。我們可以使用par()和seq()方法來在順序集合及其並行版本之間進行相互轉換。
四.Actor
簡介:
Acotr模式是一種併發模型與另一種模型共享內存完全相反,Actor模型share nothing。
所有線程(或進程)通過消息傳遞方式進行合作,這些線程(或進程)稱爲Actor,共享內存更適合單機多核的併發編程。
特點:
- 保證互斥訪問的活動對象。
- 一個Actor將只會處理一條消息。Actor模型具有與生俱來的線程安全性。
- 多個Actor併發地運行,同時處理多條消息。
- Actor是異步。
- 不會阻塞調用者。
- 不用顯示創建一個線程池,顯示調度任務。
- 線程並不和Actor綁定--一個線程池服務於多個Actor。
- java創建共享可變變量,並使用同步原語來提供線程安全性。使用JDK 庫很難在短時間內做到正確的併發。
注意:
- 更多依賴無狀態Actor,少用有狀態Actor。
- 確保Actor之間傳遞消息是不可變對象(case,String,Int等)。保證我們不會無意間修改共享狀態。
- 儘量避免使用ask().雙向通信不是一個好主意。“發送並忘記”(!)模型好得多。
示例:
統計字符串的次數。
import akka.actor._
import scala.collection.mutable
/**
* 接收消息
*/
class MessageActor extends Actor{
val messagesCount: mutable.Map[String, Int] =mutable.Map()
override def receive: Receive = {
case Play(role) =>
val currentCount = messagesCount.getOrElse(role, 0)
messagesCount.update(role, currentCount + 1)
println(s"Playing $role")
case ReportCount(role) =>
sender ! messagesCount.getOrElse(role,0)
}
}
case class Play(role: String)
case class ReportCount(role: String)
import akka.actor._
import akka.util.Timeout
import akka.pattern.Patterns
import scala.concurrent.Await
import scala.concurrent.duration._
/**
* Acotr模式是一種併發模型與另一種模型共享內存完全相反,Actor模型share nothing。
* 所有線程(或進程)通過消息傳遞方式進行合作,這些線程(或進程)稱爲Actor,共享內存更適合單機多核的併發編程。
*/
object UseActor extends App{
val system = ActorSystem("sample")
val depp = system.actorOf(Props[MessageActor])
val hanks = system.actorOf(Props[MessageActor])
/**
*tell屬於發了就完,什麼都不管的類型。
*
*/
depp ! Play("Depp1")
hanks ! Play("Hanks1")
depp ! Play("Depp1")
depp ! Play("Depp2")
println("Sent roles to play ")
/**
* 詢問(ask ?)模式,因爲發送一條消息並等待響應可能會導致潛在的活鎖
* 消息可能永遠不會到達,設置超時時間
*/
implicit val timeout: Timeout = Timeout(2.seconds)
val depp1 = Patterns.ask(depp, ReportCount("Depp1"), timeout)
val depp2 = Patterns.ask(depp, ReportCount("Depp2"), timeout)
val hanks1 = Patterns.ask(hanks, ReportCount("Hanks1"), timeout)
val depp1Count = Await.result(depp1, timeout.duration)
val depp2Count = Await.result(depp2, timeout.duration)
val hanks1Count = Await.result(hanks1, timeout.duration)
println(s"Depp played Depp1 $depp1Count time(s)")
println(s"Depp played Depp2 $depp2Count time(s)")
println(s"Hanks played Hanks1 $hanks1Count time(s)")
val terminateFuture = system.terminate()
Await.ready(terminateFuture, Duration.Inf)
}
結果:
Playing Depp1
Playing Hanks1
Sent roles to play
Playing Depp1
Playing Depp2
Depp played Depp1 2 time(s)
Depp played Depp2 1 time(s)
Hanks played Hanks1 1 time(s)
參考《Scala實用指南》