Скала, проверь, вышел ли Актер - PullRequest
5 голосов
/ 28 ноября 2010

в Scala 2.8, когда я начинаю актеров, я могу общаться через передачу сообщений.Это, в свою очередь, означает, что я могу отправить окончательное сообщение Exit () или все, что я решу, в соответствии с моим протоколом.

Но как я буду проверять, вышел ли актер?Я легко могу представить себе задачу, когда главный актер запускает несколько рабочих актеров, а затем просто ждет ответов, каждый раз проверяя, был ли это окончательный ответ (т.е. все ли актеры все еще работают или они все ушли?).

Конечно, я могу позволить им всем отправить обратно сообщение "Я закончил", а затем сосчитать их, но это как-то неудовлетворительно.

Что является наилучшей практикой при тестировании на завершение работника?-actors?

РЕДАКТИРОВАТЬ # 1

Эй, ребята, я изучаю фьючерсы, но у меня проблемы.Может кто-нибудь объяснить, почему этот код не работает:

package test
import scala.actors.Futures._

object FibFut extends Application{

    def fib(i:Int):Int = 
        if(i<2)
            1
        else
            fib(i-1)+fib(i-2)

    val f = future{ fib(3) }

    println(f())    

}

Это работает, если я определю функцию fib внутри тела будущего.Это должно быть предметом, но я не получаю никаких ошибок с вышесказанным, он просто зависает.Кто-нибудь?

РЕДАКТИРОВАТЬ # 2

Кажется, что расширение приложения не было хорошим способом.Определение основного метода заставило все работать.Ниже приведен код, который я искал, поэтому Futures поднимите палец вверх:)

package test

import scala.actors.Futures._

object FibFut {

  def fib(i: Int): Int = if (i < 2) 1 else fib(i - 1) + fib(i - 2)

  def main(args: Array[String]) {

    val fibs = for (i <- 0 to 50) yield future { fib(i) }

    for (future <- fibs) println(future())

  }

}

Ответы [ 3 ]

3 голосов
/ 28 ноября 2010

Лично я фанат сообщений "Я закончил";это хороший способ управлять распределением работы, и в качестве бонуса вы уже знаете, когда все дети закончили то, что они делают. и подождите, пока все не будет готово, проверьте scala.actors.Futures.Вы можете попросить его выполнить некоторые вычисления:

val futureA = Futures.future {
  val a = veryExpensiveOperation
  (a,"I'm from the future!")
}

, а затем подождать, пока все завершится, если вы сделали несколько запросов:

Futures.awaitAll(600*1000, futureA, futureB, futureC, futureD)
// Returns once all of A-D have been computed
val actualA = futureA()   // Now we get the value
2 голосов
/ 28 ноября 2010

Некоторое время назад я написал пост о связывании актеров в Scala.Связывание актеров - это идиоматический [и самый простой] способ отслеживать актеров в Erlang, Scala Actors и других библиотеках актеров.По умолчанию, когда вы связываете двух актеров, и один из них умирает, другой тоже немедленно умирает (если только актер не улавливает / обрабатывает сигнал выхода):

scala> case object Stop
defined module Stop

scala>

scala> val actor1 = actor {
     |    loop {
     |       react {
     |          case Stop =>
     |             println("Actor 1: stop")
     |             exit()
     |          case msg => println(msg)
     |             }
     |         }
     | }
actor1: scala.actors.Actor = scala.actors.Actor$$anon$1@1feea62

scala>

scala> val actor2 = actor {
     |    link(actor1)
     |    self.trapExit = true
     |    loop {
     |       react {
     |          case msg => println(msg)
     |             }
     |         }
     | }
actor2: scala.actors.Actor = scala.actors.Actor$$anon$1@1e1c66a

scala> actor1.start
res12: scala.actors.Actor = scala.actors.Actor$$anon$1@1feea62

scala> actor2.start
res13: scala.actors.Actor = scala.actors.Actor$$anon$1@1e1c66a

scala> actor1 ! Stop
Actor 1: stop

scala> Exit(scala.actors.Actor$$anon$1@1feea62,'normal)  // Actor 2 received message, when Actor1 died

Более сложный и гибкий способ - использование супервизоров (супервизор)поведение в Erlang, супервайзеры в библиотеке актеров Akka и т. д.).Супервизор (будучи самим актером) контролирует ряд других действующих лиц и перезапускает их в соответствии с заданной стратегией (перезапустите всех актеров, если один из них умрет, перезапустите только одного актера, если он умрет).

0 голосов
/ 29 ноября 2010

Хорошо, все, я придумала решение, используя функцию getState класса актера.В решении я использовал идею из этой темы: Лучший способ заглянуть в почтовый ящик актера Scala , в котором используется responseWithin (0).Я столкнулся с проблемой при использовании реакции и цикла, когда программа просто блокировала бы большие вычисления.Это было решено заменой цикла на while (true) и responseWithin (int) на receiveWithin (int).

Мое решение выглядит следующим образом (будьте осторожны, большой кодовый кусок):

package test

import scala.actors._
import scala.actors.Actor.State._

case class Computation(index: Int, a: () ⇒ Int)
case class Result(i: String)
object Main {
  def main(args: Array[String]) {
    val m = new Master
    m.start
  }
}

class Master extends Actor {

  val N = 40
  var numberOfAnswers = 0

  def fib(x: Int): Int =
    if (x < 2)
      1
    else
      fib(x - 1) + fib(x - 2)

  val computers = for (i ← 0 to N) yield new Computer

  def act {

    for (i ← 0 until computers.size) {
      computers(i).start
      computers(i) ! Computation(i, () => fib(i))
    }

    println("done Initializing actors")
    while (true) {
      receiveWithin(1000) {

        case Result(i) =>
          val numberDone = computers.map(_.getState == Terminated).filter(_ == true).length
          println(i)
          numberOfAnswers += 1

        case TIMEOUT =>
          val allDone = computers.map(_.getState == Terminated).reduceRight(_ && _)
          println("All workers done?:" + allDone)
          println("# of answers:" + numberOfAnswers)
          if (allDone)
            exit()
      }
    }

  }

}

class Computer extends Actor {

  def act {
    loop {
      react {
        case Computation(i, f) ⇒
          sender ! Result("#" + i + " Res:" + f())
          exit()
      }
    }
  }

}

Программа рассчитывает числа Фибоначчи (наихудшим из возможных способов).Идея состоит в том, чтобы просто протестировать использование нескольких потоков для больших рабочих нагрузок.Следующая строка проверяет, должен ли еще актер завершить свою работу:

computers.map(_.getState == Terminated).reduceRight(_ && _)

, где компьютеры относятся к типу IndexedSeq [Computer].Хитрость в том, что, используя сообщение TIMEOUT, я могу периодически проверять, все ли работы выполнены, и действовать соответствующим образом (в этом случае выйти, когда больше нет активных работников).Я пользуюсь тем фактом, что каждый работник отправляет результаты, прежде чем они выходят.Таким образом, я знаю, что всегда буду получать результаты и обрабатывать их до того, как они будут отображены как Прерванные.

Может кто-нибудь прокомментировать тот факт, что программа «зависает» (прекращает получать сообщения), когда я используюреагировать и зацикливаться вместо while (true) и получать?

...