7. actor
http://www.scala-lang.org/docu/files/actors-api/actors_api_guide.html#
Scala中处理并发,有很多选择:
l actor消息模型,类似Erlang,首选,Lift和akka也实现了自己的actor模型。
l Thread、Runnable
l java.util.concurennt
l 3rd并发框架如Netty,Mina
7.1. actor模型
Java内置线程模型 |
Scala actor模型 |
“共享数据-锁”模型(share data and lock) |
share nothing |
每个object有一个monitor,监视多线程对共享数据的访问 |
不共享数据,actor之间通过message通讯 |
加锁的代码段用synchronized标识 |
|
死锁问题 |
|
每个线程内部是顺序执行的 |
每个actor内部是顺序执行的 |
|
|
7.2. 多核计算
对比如下的算法:
def perfect(n:Int) = n==(1 until n filter (n%_==0) sum) val n = 33550336 // 串行计算 n to n+10 foreach (i=>println(perfect(i))) |
def perfect(n:Int) = n==(1 until n filter (n%_==0) sum) val n = 33550336 // 并行计算 class T1(n:Int) extends Thread { override def run(){println(perfect(n))}} n to n+10 foreach (i=>new T1(i).start) |
耗时:8297 |
耗时:5134 |
|
|
单线程串行计算,不能很好发挥多核优势 |
多线程并行计算,平均分配到多核,更快 |
上面是Java的写法,也可以用Scala的actor写法:
Scala写法1:
import actors.Actor,actors.Actor._
class A1 extends Actor {
def act { react { case n:Int=>println(perfect(n)) }}}
n to n+10 foreach (i=>{ (new A1).start ! i})
Scala写法2:
val aa = Array.fill(11)(actor { react { case n:Int=>println(perfect(n)) }})
n to n+10 foreach (i=>aa(i-n) ! i)
或者:
n to n+10 foreach (i=> actor { react { case n:Int=>println(perfect(n)) }} ! i)
7.3. Actor用法
Scala会建立一个线程池共所有Actor来使用。receive模型是Actor从池中取一个线程一直使用;react模型是Actor从池中取一个线程用完给其他Actor用
实现方式1:
import scala.actors._
object Actor1 extends Actor { // 或者class
// 实现线程
def act() { react { case _ =>println("ok"); exit} }
}
//发送消息:
Actor1.start ! 1001 // 必须调用start
实现方式2:
import scala.actors.Actor._
val a2 = actor { react { case _ =>println("ok") } } // 马上启动
//发送消息:
a2 ! "message" // 不必调用start
提示:
! |
发送异步消息,没有返回值。 |
!? |
发送同步消息,等待返回值。(会阻塞发送消息语句所在的线程) |
!! |
发送异步消息,返回值是 Future[Any]。 |
? |
不带参数。查看 mailbox 中的下一条消息。 |