scala原生的acotor在任务结束之后并不会被回收,这也就是说,我无法无限制的创建actor。例如在一个HTTP服务器中,如果每个请求都创建一个新的actor处理,这样不久之后就会内存溢出。今天对scala和akka的actor内存使用情况做了简单测试
测试代码如下
import akka.actor.Actor
import akka.actor.Actor.spawn
import akka.actor.PoisonPill
import java.io.FileOutputStream
import java.io.OutputStream
import java.io.OutputStreamWriter
case class Work(val index: Int, val output: OutputStream)
case class Result(val value: Double)
object Task {
def main(args: Array[String]) {
Thread.sleep(15000)
new AkkaActorTask(10000000).execute()
}
}
trait CalculateTask {
val output: OutputStream
val taskCount: Int
def sendWork(work: Work)
def execute() {
for (i <- 1 to taskCount) {
sendWork(Work(i, output))
}
}
}
class AkkaActorTask(val taskCount: Int) extends CalculateTask {
val output = Work.akkaTaskOutput
def sendWork(work: Work) {
spawn {
Work.doWork(work)
}
}
}
class ScalaActorTask(val taskCount: Int) extends CalculateTask {
override val output = Work.scalaTaskOutput
def sendWork(work: Work) {
val actor = new ScalaActorWorker
actor.start()
actor ! work
}
class ScalaActorWorker extends scala.actors.Actor {
def act = {
react {
case work:Work => Work.doWork(work); exit()
}
}
}
}
object Work {
val resultName = "result-"
val akkaTaskOutput = new FileOutputStream(resultName + "akka")
val scalaTaskOutput = new FileOutputStream(resultName + "scala")
def doWork(work: Work) {
work.output.write("log(%d) = %f".format(work.index, math.log(work.index)).getBytes())
work.output.flush()
}
}
程序说明:
计算从0到10,000,000的整形的自然对数(math.log)并写入文件
分别选择Scala和Akka的actor实现,(spwan是一种一次性非常轻量级的akka actor)
下面是测试结果,
机器配置
CPU:Intel(R) Core(TM)2 Duo CPU E8400 @ 3.00GHz
RAM :4G
JAVA_OPTS: Xms100m Xmx100m
Akka actor performance
没有内存泄漏,100m可以负荷连续不断的actor创建
Scala actor performance
执行没多久就outOfMemory
可以很明显看到scala actor gc的问题,即使exit了,也不会被回收。官方的说法是一个actor exit之后甚至可能被重新start。
scala.concurrent.ops也有个spawn方法可以执行异步操作http://www.scala-lang.org/api/current/index.html#scala.concurrent.ops$