Scala, проверьте, вышел ли Актер

110
13

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


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


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


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


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


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


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 внутри тела будущего. Это должно быть областью видимости, но я не получаю никаких ошибок с вышеупомянутым, это просто зависает. Кто-нибудь?


Edit # 2


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


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())

}

}

спросил(а) 2021-01-19T20:04:20+03:00 6 месяцев, 2 недели назад
1
Решение
89

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


Но если вы действительно хотите развернуть какую-то работу один раз и дождаться, когда все будет готово, проверьте 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

ответил(а) 2021-01-19T20:04:20+03:00 6 месяцев, 2 недели назад
78

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


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 Actors library, и т.д). Супервизор (сам по себе актер) контролирует ряд других участников и перезапускает их в отношении определенной стратегии (перезапустите всех актеров, если умрет, перезапустите только одного актера, когда он умрет).

ответил(а) 2021-01-19T20:04:20+03:00 6 месяцев, 2 недели назад
46

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


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


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) и получаю?

ответил(а) 2021-01-19T20:04:20+03:00 6 месяцев, 2 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема