Akka是一個構建在JVM上,基於Actor模型的的並發框架,為構建伸縮性強,有彈性的響應式並發應用提高更好的平台。本文主要是個人對Akka的學習和應用中的一些理解。
Actor模型
Akka的核心就是Actor,所以不得不說Actor,Actor模型我通俗的舉個例子,假定現實中的兩個人,他們只知道對方的地址,他們想要交流,給對方傳遞信息,但是又沒有手機,電話,網絡之類的其他途徑,所以他們之間只能用信件傳遞消息,很像現實中的的郵政系統,你要寄一封信,只需根據地址把信投寄到相應的信箱中,具體它是如何幫你處理送達的,你就不需要了解了,你也有可能收到收信人的回復,這相當於消息反饋。上述例子中的信件就相當於Actor中的消息,Actor與Actor之間只能通過消息通信。當然Actor模型比這要復雜的多,這里主要是簡潔的闡述一下Actor模型的概念。
Akka中Actors模型
-
對並發模型進行了更高的抽象
-
異步、非阻塞、高性能的事件驅動編程模型
-
輕量級事件處理(1GB內存可容納百萬級別個Actor)
為什么Actor模型是一種處理並發問題的解決方案?
一開始我也不怎么理解,腦子里的一貫思維是處理並發問題就是如何保證共享數據的一致性和正確性,為什么會有保持共享數據正確性這個問題呢?無非是我們的程序是多線程的,多個線程對同一個數據進行修改,若不加同步條件,勢必會造成數據污染。那么我們是不是可以轉換一下思維,用單線程去處理相應的請求,但是又有人會問了,若是用單線程處理,那系統的性能又如何保證。Actor模型的出現解決了這個問題。
Actor模型概圖:
從上圖中我們可以看到,Actor與Actor之前只能用消息進行通信,當某一個Actor給另外一個Actor發消息,消息是有順序的,你只需要將消息投寄的相應的郵箱,至於對方Actor怎么處理你的消息你並不知道,當然你也可等待它的回復。
JVM中的Actor有以下幾個特點:
-
每個Actor都有對應一個郵箱
-
Actor是串行處理消息的
-
Actor中的消息是不可變的
其實只從上面一些描述來看,並不能看出Actor在處理並發問題上的有什么優勢。
但我總結了兩點:簡化並發編程,提升程序性能
1.簡化並發編程:
我們一開始說過並發導致最大的問題就是對共享數據的操作,我們在面對並發問題時多采用的是
用鎖去保證共享數據的一致性,但這同樣也會帶來其他相關問題,比如要去考慮鎖的粒度(對方法,程序塊等),鎖的形式(讀鎖,寫鎖等)等問題,這些問題對並發程序來說是至關重要的,但一個初寫並發程序的程序員來說,往往不能掌控的很好,這無疑給程序員在編程上提高了復雜性,而且還不容易掌控,但使用Actor就不導致這些問題,首先Actor的消息特性就覺得了在與Actor通信上不會有共享數據的困擾,另外在Actor內部是串行處理消息的,同樣不會對Actor內的數據造成污染,用Actor編寫並發程序無疑大大降低了編碼的復雜度。
2.提升程序性能:
我們之前說過既然用單線程處理,那如何保證程序的性能?首先Actor是非常輕量級的,你可以再程序中創建許多個Actor,而且Actor是異步的,那么如何利用它的這個特性呢,我們要做的就是把相應的並發事件盡可能的分割成一個個小的事件,讓每個Actor去處理相應的小事件,充分去利用它異步的特點,來提升程序的性能。
其實Scala中原生的Actor並不能完成很多事,不是一套完整的並發解決方案,不適合用於生產環境,比如錯誤恢復,狀態持久化等,所以在較新版本的Scala類庫中,Akka包已經取代了原生的Actor。
Akka
那下面我們來簡單說說Akka吧,Akka作為一套成熟的並發解決方案,已經被業界大量采用,尤其是在金融,游戲等領域,Akka中的容錯機制,持久化,遠程調用,日志等都是很重要的模塊,這些內容都會在這個系列的后續文章里一一講解。下面就以一個入門Akka程序來結束本篇文章吧。現在我們假設有一個家居機器人,我們只需要給它發送消息它便會幫我們處理相應的事情,現在我們用程序來模擬這個場景:源碼鏈接
本示例使用Scala語言,構建工具為SBT,IDE為IntelliJ IDEA.
1.首先創建一個基於SBT的Scala工程
build.sbt
配置:
name := "Example_01" version := "1.0" scalaVersion := "2.11.8" val akkaVersion = "2.4.16" libraryDependencies += "com.typesafe.akka" %% "akka-actor" % akkaVersion
2.我們來定義一些消息:
trait Action{ val message: String val time: Int } case class TurnOnLight(time: Int) extends Action { // 開燈消息 val message = "Turn on the living room light" } case class BoilWater(time: Int) extends Action { // 燒水消息 val message = "Burn a pot of water" }
3.我們利用Actor來實現一個模擬機器人:
class RobotActor extends Actor { val log = Logging(context.system, this) def receive: Receive = { //機器人接受指令 case t: TurnOnLight => log.info(s"${t.message} after ${t.time} hour") case b: BoilWater => log.info(s"${b.message} after ${b.time} hour") case _ => log.info("I can not handle this message") } }
4.我們去測試這個機器人:
來源於:https://segmentfault.com/a/1190000009256507 https://godpan.me/