一個超簡單的akka actor例子
抛開複雜的業務邏輯,讓我們從一個超級簡單的例子學習Akka Actor的用法。 Scala cookbook的作者Alvin Alexander在他的網站上提供了兩個例子。
本文翻譯、整理于他的兩篇文章。
下面幾行代碼就實作了一個actor。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| import akka.actor.Actor
import akka.actor.ActorSystem
import akka.actor.Props
class HelloActor extends Actor {
def receive = {
case "hello" => println("您好!")
case _ => println("您是?")
}
}
object Main extends App {
val system = ActorSystem("HelloSystem")
// 預設的Actor構造函數
val helloActor = system.actorOf(Props[HelloActor], name = "helloactor")
helloActor ! "hello"
helloActor ! "喂"
}
|
- 1到3行是引入必要的類
- 第5行定義了一個Actor, 實作了receive方法, 如果接收到"hello",傳回一個禮貌性的"您好", 如果接收到其它消息,傳回"您是?"
- 第12行定義了一個main對象
- 我們需要一個ActorSystem,是以在第13行建立了一個
- 第15行建立了一個HellActor的執行個體,傳回結果類型為ActorRef。 這裡HelloActor我們調用預設的構造函數,你也可以調用特定的帶參數的構造函數
- 第16,17行我們發送了兩個消息給這個actor, actor應該能收到這兩條消息并處理
!
是一個簡化發送消息的操作符, ScalaActorRef為ActorRef定義的一個隐式方法。
1
2
3
| trait ScalaActorRef { ref: ActorRef ⇒
def !(message: Any)(implicit sender: ActorRef = null): Unit
}
|
假定你已經安裝了scala和sbt。建立一個檔案夾,在此檔案夾中建立一個
build.sbt
,内容如下:
1
2
3
4
5
| name := "Hello Test #1"
version := "1.0"
scalaVersion := "2.11.4"
libraryDependencies += "com.typesafe.akka" %% "akka-actor" % "2.3.9"
|
我機器上安裝scala的版本為
2.11.4
,你可以調整為你機器上合适的版本,以及相應的akka的版本。
将上述actor的代碼複制到此檔案夾下的
HelloActor.scala
檔案中。
執行下面的指令:
輸出結果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| C:\akka>sbt run
[info] Set current project to Hello Test #1 (in build file:/C:/akka/)
[info] Updating {file:/C:/akka/}akka...
[info] Resolving org.scala-lang#scala-library;2.11.4 ...
[info] Resolving com.typesafe.akka#akka-actor_2.11;2.3.9 ...
[info] Resolving org.scala-lang#scala-library;2.11.5 ...
[info] Resolving com.typesafe#config;1.2.1 ...
[info] Resolving org.scala-lang#scala-compiler;2.11.4 ...
[info] Resolving org.scala-lang#scala-reflect;2.11.4 ...
[info] Resolving org.scala-lang.modules#scala-xml_2.11;1.0.2 ...
[info] Resolving org.scala-lang.modules#scala-parser-combinators_2.11;1.0.2 ..
.
[info] Resolving jline#jline;2.12 ...
[info] Done updating.
[warn] Scala version was updated by one of library dependencies:
[warn] * org.scala-lang:scala-library:2.11.4 -> 2.11.5
[warn] To force scalaVersion, add the following:
[warn] ivyScala := ivyScala.value map { _.copy(overrideScalaVersion = true) }
[warn] Run 'evicted' to see detailed eviction warnings
[info] Running Main
您好!
您是?
|
Ctrl
+
C
可以終止程式的運作。
這裡還有一個更複雜的例子,涉及到兩個actor的互動。 就像兩個人在乒乒乓乓的打乒乓球。 兩個actor來回的ping pang,直到達到特定的次數才停止。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
| import akka.actor._
case object PingMessage
case object PongMessage
case object StartMessage
case object StopMessage
class Ping(pong: ActorRef) extends Actor {
var count = 0
def incrementAndPrint { count += 1; println("ping") }
def receive = {
case StartMessage =>
incrementAndPrint
pong ! PingMessage
case PongMessage =>
if (count > 9) {
sender ! StopMessage
println("ping stopped")
context.stop(self)
} else {
incrementAndPrint
sender ! PingMessage
}
}
}
class Pong extends Actor {
def receive = {
case PingMessage =>
println(" pong")
sender ! PongMessage
case StopMessage =>
println("pong stopped")
context.stop(self)
context.system.shutdown()
}
}
object PingPongTest extends App {
val system = ActorSystem("PingPongSystem")
val pong = system.actorOf(Props[Pong], name = "pong")
val ping = system.actorOf(Props(new Ping(pong)), name = "ping")
// start them going
ping ! StartMessage
}
|
這裡定義了兩個actor: Ping和Pang。
- Ping 接收StartMessage和 PongMessage。 StartMessage是一個啟動消息,由main對象發送,PongMessage來自Pong actor,如果次數還未達到,它繼續發送PingMessage。
- Pong 接收StopMessage和 PingMessage。 如果接收到PingMessage,它就發送一個PongMessage, 如果是StopMessage, 停止ActorSystem
這裡調用了Ping的帶參數的構造函數
Props(new Ping(pong))
參考文檔
- Simple Scala Akka Actor examples (Hello, world examples)
- A 'Ping Pong' Scala Akka actors example