我正在寻找我的爱好项目的帮助。我试图找到一个更好的方法,我的拉模式中的管理器将如何处理任务列表更新(需要完成的工作列表)
我已经实现了一个拉模式,其中有一个Job Factory,Manager和一个Worker。管理器在akka调度程序的帮助下从作业工厂获取新作业。每当有新工作时,工人就会得到通知并开始咀嚼。
在我的实现中可能是一个怪癖是,Worker会产生必须完成的新任务。目前,我已经通过从工作者到自身的递归消息解决了这个问题。
这是非常简单的想法:
class Worker extends Actor {
def receive = {
case Work0 ⇒ self ! Work1
case Work1 ⇒ // ...
}
}
但是,我不喜欢这种方法。我希望现有的任务列表在Manager端进行扩展,如果出现新任务,让工作人员将新的作业发送给Manager。
class Worker extends Actor {
def receive = {
case Work0 ⇒ Manager ! Work1
case Work1 ⇒ // ...
}
}
以下是如何在Manager内创建能够动态更改的工作缓冲区的解决方案。只要Worker将工作发送给Manager,它就会被添加到缓冲区之上。最终,Worker将遍历管理器在缓冲区内的所有任务。
这个例子没有拉模式本身的任何管道,这个想法只是为了测试如何让缓冲区工作。
import akka.actor.Actor
import akka.actor.ActorSystem
import akka.actor.Props
import scala.collection.mutable
import scala.collection.mutable.{ArrayBuffer, ListBuffer}
class Manager extends Actor {
var iterator: Iterator[Int] = Iterator.empty
var buffer: Option[mutable.ArrayBuffer[Int]] = None
var iteratorCounter: Int = 0
def receive = {
case MyBuffer(workBuffer: mutable.ArrayBuffer[Int]) ⇒
buffer = Some(workBuffer)
iterator = workBuffer.iterator
case "iterate" ⇒
if (iterator.hasNext) {
iterator.next() // This will be sent to worker as a Task to process
iteratorCounter += 1
} else if (buffer.get.length > iteratorCounter) {
iterator = buffer.get.iterator
iterator = iterator.drop(iteratorCounter)
} else {
iteratorCounter = 0
}
case "add" ⇒ // "Worker adds" new stuff to Manager
val random = scala.util.Random
val newVal = random.nextInt(100)
val append = (buf: Option[ArrayBuffer[Int]], element: Int) => Some(buf.get += element)
buffer = append(buffer, newVal)
case _ => println("huh?")
}
}
case class MyBuffer(workBuffer: ArrayBuffer[Int])
val buffer = mutable.ArrayBuffer(1,2,3,4,5,6,7,8,9,10)
val system = ActorSystem("PullPattern")
val helloActor = system.actorOf(Props(new Manager))
helloActor ! MyBuffer(buffer)
var a = 0
for (a <- 1 to 5) {
helloActor ! "iterate"
}
a = 0
for (a <- 1 to 3) {
helloActor ! "add"
}
a = 0
for (a <- 1 to 10) {
helloActor ! "iterate"
}
我的问题:
答案 0 :(得分:2)
我建议使用mutable.ArrayBuffer
排队工作,而Iterator
将工作推入/拉出队列,而不是immutable.Queue
和enqueue/dequeue
。从您的示例代码中可以看出,您正在以FIFO方式工作,因此队列最适合您的需求。
我不建议使用Iterator
(可变)作为指针。特别是,除了next/hasNext
之外,在调用方法之后使用迭代器是不安全的(参见Scala doc)。使用FIFO队列时,不需要迭代器。
让经理人保持内部队列/地图/等以跟踪工作人员的任务是很常见的。只要适用,我会在可变集合中选择一个不可变的集合。如果有必要,请将不可变集合设为private var
,但如果您想避免任何hot-swap
,则可以通过context.become var
演员的内部状态。
Re:使用Akka actor的拉模型的工人系统,这里是nice article。 Lightbend还提供了一个基于拉模型的distributed worker system示例应用程序。