斯卡拉调度员 - 工人演员模式

时间:2012-12-06 13:19:37

标签: scala actor dispatcher

我正在尝试使用标准的scala.actors包为Scala设计一个dispatcher-worker actor模式。

调度员从java.util.concurrent.LinkedBlockingQueue接收工作并将其发送给要处理的工作人员。完成所有工作后,调度员应该告诉每个工人退出,然后它也应该退出。这是我提出的代码,但是当所有工作完成时它会挂起(我认为调度程序的队列中有待处理的'GiveMeWork消息):

import java.util.concurrent.LinkedBlockingQueue
import scala.actors.Actor

object Dispatcher
extends Actor {
  println("Dispatcher created")

  def act() {
    val workers = (1 to 4).map(id => (new Worker(id)).start())

    loop {
      react {
        case 'GiveMeWork =>
          // println("Worker asked for work")
          val (time, i) = workQueue.take()
          if (time == 0) {
            println("Quitting time")
            workers.foreach(_ !? 0L)
          } else {
            println("Arrival at dispatcher: i: " + i + " dispatch time: " +
                    time + ", elapsed: " + (System.nanoTime() - time))
            sender ! time
          }
        case 'Quit =>
          println("Told to quit")
          sender ! 'OffDuty
          exit()
      }
    }
  }
}

class Worker(id: Int)
extends Actor {
  println("Worker(" + id + ") created")
  var jobs = 0

  def act() {
    Dispatcher ! 'GiveMeWork

    loop {
      react {
        case time: Long =>
          if (time == 0) {
            println("Worker(" + id + ") completed " + jobs + " jobs")
            sender ! 'OffDuty
            exit()
          } else {
            println("Arrival at worker(" + id + "): dispatch time: " +
                    time + ", elapsed: " + (System.nanoTime() - time))
            Thread.sleep(id)
            jobs += 1
            Dispatcher ! 'GiveMeWork
          }
      }
    }
  }
}

val workQueue = new LinkedBlockingQueue[(Long, Int)](1000)

Dispatcher.start()

for (i <- 0 until 5000) {
  Thread.sleep(1)
  workQueue.put((System.nanoTime(), i))
}

workQueue.put((0L, 0))

println("Telling Dispatcher to quit")
Dispatcher !? 'Quit

1 个答案:

答案 0 :(得分:3)

有一场比赛:

val (time, i) = workQueue.take()

所有工作都已完成,包括workQueue.put((0L, 0)),所以它将永远等待。

同时使用不同类型的并发是一个坏主意。

Dispatcher可以通知任务源有关任务限制的信息:

import scala.actors.{Actor, OutputChannel}
import scala.collection.mutable.Queue

case class Task(time: Long, i: Int)
case object GiveMeWork
case object Quit
case object OffDuty

object Dispatcher extends Actor {
  println("Dispatcher created")

  def act() {
    val workers = (1 to 4).map(id => (new Worker(id)).start())
    val waitingWorkers = Queue[OutputChannel[Any]](workers: _*)
    val tasks = Queue[Task]()
    var workSender: Option[OutputChannel[Any]] = None

    loop {
      react {
        case GiveMeWork =>
          if (!tasks.isEmpty) sender ! tasks.dequeue()
          else waitingWorkers enqueue sender

          workSender map { _ ! GiveMeWork }
          workSender = None
        case t: Task =>
          if (!waitingWorkers.isEmpty) waitingWorkers.dequeue() ! t
          else tasks enqueue t

          if (tasks.length < 1000) sender ! GiveMeWork
          else workSender = Some(sender)
        case Quit =>
          println("Told to quit")
          workers.foreach{ _ ! Quit }
          sender ! OffDuty
          exit()
      }
    }
  }
}

class Worker(id: Int)
extends Actor {
  var jobs = 0

  def act() {
    loop {
      react {
        case t: Task =>
          Thread.sleep(id)
          jobs += 1
          Dispatcher ! GiveMeWork
        case Quit =>
          println("Worker(" + id + ") completed " + jobs + " jobs")
          sender ! OffDuty
          exit()
      }
    }
  }
}

Dispatcher.start()

for (i <- 0 until 5000) {
  Thread.sleep(1)
  Dispatcher !? Task(System.nanoTime(), i)
}

println("Telling Dispatcher to quit")
Dispatcher !? Quit