了解 actor 如何提供新的應用程序代碼建模方法
主要芯片廠商已經開始提供同時運行兩個或更多個核的芯片(雖然不一定更快)
關於本系列
Ted Neward 潛心研究 Scala 編程語言
在 前一篇文章 中
這些理論問題太沉悶了
真正提供並發性的是 Scala 的 actor
什麼是
僅僅傳遞消息並不能避免錯誤的並發代碼的所有問題
這不算是對 actor 模型的正規描述
Scala actor
使用 actor 根本不困難
清單
import scala
package com
{
object Actor
{
def main(args : Array[String]) =
{
val badActor =
actor
{
receive
{
case msg => System
}
}
badActor !
}
}
}
這裡同時做了兩件事
首先
下一步是使用 actor 方法創建 actor 本身
請記住
消息交付給 actor 之後
一定要注意一點
例如
清單
object Actor
{
case class Speak(line : String);
case class Gesture(bodyPart : String
case class NegotiateNewContract;
def main(args : Array[String]) =
{
val badActor =
actor
{
receive
{
case NegotiateNewContract =>
System
case Speak(line) =>
System
case Gesture(bodyPart
System
case _ =>
System
}
}
badActor ! NegotiateNewContract
badActor ! Speak(
badActor ! Gesture(
badActor ! Speak(
}
}
到目前為止
糾正這個問題需要對代碼做以下修改
把 receive 塊放在一個接近無限的循環中
創建一個新的 case 類來表示什麼時候處理全部完成了
清單
object Actor
{
case class Speak(line : String);
case class Gesture(bodyPart : String
case class NegotiateNewContract;
case class ThatsAWrap;
def main(args : Array[String]) =
{
val badActor =
actor
{
var done = false
while (! done)
{
receive
{
case NegotiateNewContract =>
System
case Speak(line) =>
System
case Gesture(bodyPart
System
case ThatsAWrap =>
System
done = true
case _ =>
System
}
}
}
badActor ! NegotiateNewContract
badActor ! Speak(
badActor ! Gesture(
badActor ! Speak(
badActor ! ThatsAWrap
}
}
這下行了!使用 Scala actor 就這麼容易
並發地執行動作
上面的代碼沒有反映出並發性 — 到目前為止給出的代碼更像是另一種異步的方法調用形式
為了證明在幕後確實有多個線程存在
清單
object Actor
{
case class Speak(line : String);
case class Gesture(bodyPart : String
case class NegotiateNewContract;
case class ThatsAWrap;
def main(args : Array[String]) =
{
def ct =
val badActor =
actor
{
var done = false
while (! done)
{
receive
{
case NegotiateNewContract =>
System
case Speak(line) =>
System
case Gesture(bodyPart
System
case ThatsAWrap =>
System
done = true
case _ =>
System
}
}
}
System
badActor ! NegotiateNewContract
System
badActor ! Speak(
System
badActor ! Gesture(
System
badActor ! Speak(
System
badActor ! ThatsAWrap
}
}
運行這個新示例
main 線程(所有 Java 程序都以它開始)
Thread
因此
但是
清單
package com
{
import concurrent
import concurrent
object ProdConSample
{
class Drop
{
private val m = new MailBox()
private case class Empty()
private case class Full(x : String)
m send Empty() // initialization
def put(msg : String) : Unit =
{
m receive
{
case Empty() =>
m send Full(msg)
}
}
def take() : String =
{
m receive
{
case Full(msg) =>
m send Empty(); msg
}
}
}
def main(args : Array[String]) : Unit =
{
// Create Drop
val drop = new Drop()
// Spawn Producer
spawn
{
val importantInfo : Array[String] = Array(
);
importantInfo
drop
}
// Spawn Consumer
spawn
{
var message = drop
while (message !=
{
System
message = drop
}
}
}
}
}
盡管看到 Scala 如何簡化這些代碼很有意思
清單
object ProdConSample
{
case class Message(msg : String)
def main(args : Array[String]) : Unit =
{
val consumer =
actor
{
var done = false
while (! done)
{
receive
{
case msg =>
System
done = (msg ==
}
}
}
consumer !
consumer !
consumer !
consumer !
consumer !
}
}
第一個版本確實簡短多了
幸運的是
在 Scala Actors 庫中
清單
object ProdConSample
{
case class Message(msg : String)
def main(args : Array[String]) : Unit =
{
val consumer =
actor
{
var done = false
while (! done)
{
receive
{
case msg =>
System
done = (msg ==
reply(
}
}
}
System
consumer !?
System
consumer !?
System
consumer !?
System
consumer !?
System
consumer !?
}
}
如果喜歡使用 spawn 把 Producer 放在 main() 之外的另一個線程中(這非常接近最初的代碼)
清單
object ProdConSampleUsingSpawn
{
import concurrent
def main(args : Array[String]) : Unit =
{
// Spawn Consumer
val consumer =
actor
{
var done = false
while (! done)
{
receive
{
case msg =>
System
done = (msg ==
reply(
}
}
}
// Spawn Producer
spawn
{
val importantInfo : Array[String] = Array(
);
importantInfo
}
}
}
無論從哪個角度來看
但是
當然
清單
object CountingSample
{
case class Incr
case class Value(sender : Actor)
case class Lock(sender : Actor)
case class UnLock(value : Int)
class Counter extends Actor
{
override def act(): Unit = loop(
def loop(value: int): Unit = {
receive {
case Incr() => loop(value +
case Value(a) => a ! value; loop(value)
case Lock(a) => a ! value
receive { case UnLock(v) => loop(v) }
case _ => loop(value)
}
}
}
def main(args : Array[String]) : Unit =
{
val counter = new Counter
counter
counter ! Incr()
counter ! Incr()
counter ! Incr()
counter ! Value(self)
receive { case cvalue => Console
counter ! Incr()
counter ! Incr()
counter ! Value(self)
receive { case cvalue => Console
}
}
為了進一步擴展 Producer/Consumer 示例
清單
object ActorDropSample
{
class Drop
{
private case class Put(x: String)
private case object Take
private case object Stop
private val buffer =
actor
{
var data =
loop
{
react
{
case Put(x) if data ==
data = x; reply()
case Take if data !=
val r = data; data =
case Stop =>
reply(); exit(
}
}
}
def put(x: String) { buffer !? Put(x) }
def take() : String = (buffer !? Take)
def stop() { buffer !? Stop }
}
def main(args : Array[String]) : Unit =
{
import concurrent
// Create Drop
val drop = new Drop()
// Spawn Producer
spawn
{
val importantInfo : Array[String] = Array(
);
importantInfo
drop
}
// Spawn Consumer
spawn
{
var message = drop
while (message !=
{
System
message = drop
}
drop
}
}
}
可以看到
actor 還有更多特性
在規模很大的系統中
在 Scala Actors 庫中
在某些情況下
結束語
因為 actor 編程需要與
首先
第二
讓代碼更容易理解(因為消息攜帶處理所需的所有狀態)
減少 actor 訪問某些地方的共享狀態的可能性
第三
很有意思的是
actor 並不是解決所有並發性問題的萬靈藥
From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19572.html