我目前正与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中发布的工作流建议。
谢谢,
答案 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
}
}