演员邮箱溢出。斯卡拉

时间:2010-07-01 11:31:04

标签: memory scala memory-management actor

我目前正与scala中的两位演员合作。一个是 producer ,它会生成一些数据并将其发送到 parcer 。制作人通过一条消息发送HashMap[String,HashMap[Object,List[Int]]](以及标记发件人):

parcer ! (this,data)

解析器一直在等待这样的消息:

def act(){
    loop{
      react{
        case (producer, data)=> parse(data);
      }
    }
}

该计划在正常情况下运行良好。问题来自大量数据和许多消息发送(散列有大约10 ^ 4个元素,内部散列大约100个元素,列表长100),程序崩溃。它显示没有错误或异常。它只是停了下来。

问题似乎是我的制作人的工作速度比解析器快得多(目前我不想要多个解析器)。

阅读scala mailbox size limit后,我想知道我的解析器的邮箱是否达到了它的极限。该帖子还提供了一些解决方案,但我首先需要确保这是问题所在。我该怎么测试呢?

有没有办法知道演员的内存限制?如何读取邮箱中的已用/可用内存?

欢迎任何尚未在that link中发布的工作流建议。

谢谢,

1 个答案:

答案 0 :(得分:4)

首先,您无需显式传递发件人,因为无论如何,Scala actors框架都会跟踪发件人。您始终可以使用sender方法访问邮件的发件人。

从这里可以看出:scala.actors.MQueue,一个actor的邮箱是作为链表实现的,因此只受堆大小的限制。

但是,如果您担心制作人非常快且消费者非常慢,我建议您探索一种限制机制。但我不会从问题scala mailbox size limit的接受答案中推荐这种方法。

通常,在系统受到严重压力时尝试发送过载消息似乎不是一个好主意。如果您的系统太忙而无法检查过载怎么办?如果过载消息的接收者太忙而无法对其进行操作怎么办?另外,删除消息对我来说听起来不是一个好主意。我认为您希望可靠地处理所有工作项目。

另外,我不会依赖mailboxSize来确定负载。您无法区分不同的消息类型,您只能从消费者本身而不是生产者那里进行检查。

我建议使用消费者要求更多工作的方法,当他知道自己可以处理它时。

以下是一个如何实施的简单示例。

import scala.actors._
import Actor._

object ConsumerProducer {
  def main(args: Array[String]) {
    val producer = new Producer(Iterator.range(0, 10000))
    val consumer = new Consumer(producer)
  }
}

case class Produce(count: Int)
case object Finished

class Producer[T](source: Iterator[T]) extends Actor {

  start

  def act() {
    loopWhile(source.hasNext) {
      react {
        case Produce(n: Int) => produce(n)
      } 
    }
  }

  def produce(n: Int) {
    println("producing " + n)
    var remaining = n
    source takeWhile(_ => remaining > 0) foreach { x => sender ! x; remaining -= 1 }
    if(!source.hasNext) sender ! Finished
  }
}

class Consumer(producer: Actor) extends Actor {

  start

  private var remaining = 0

  def act() {
    requestWork()
    consume()
  }

  def consume(): Nothing = react {
    case Finished => println("Finished")
    case n: Int => work(n); requestWork(); consume()
  }

  def requestWork() = if(remaining < 5) { remaining += 10; producer ! Produce(10) }

  def work(n: Int) = {
    println(n + ": " + (0 until 10000).foldLeft(0) { (acc, x) => acc + x * n })
    remaining -= 1
  }
}