программа зависает при использовании нескольких фьючерсов с несколькими удаленными актерами - PullRequest
5 голосов
/ 28 июля 2010

Я запускаю двух удаленных актеров на одном хосте, которые просто повторяют все, что им отправлено.Затем я создаю другого актера, который отправляет некоторое количество сообщений (используя !!) обоим акторам и сохраняю объекты List of Future, содержащие ответы от этих акторов.Затем я перебираю этот список, извлекая результаты каждого будущего.Проблема в том, что большую часть времени некоторые фьючерсы никогда не возвращаются, даже если актер утверждает, что отправил ответ.Проблема возникает случайным образом, иногда она проходит через весь список, но большую часть времени она застревает в какой-то момент и зависает на неопределенное время.

Вот код, который создает проблему на моей машине:

Sink.scala:

import scala.actors.Actor
import scala.actors.Actor._
import scala.actors.Exit
import scala.actors.remote.RemoteActor
import scala.actors.remote.RemoteActor._

object Sink {
  def main(args: Array[String]): Unit = {
     new RemoteSink("node03-0",43001).start()
     new RemoteSink("node03-1",43001).start()
   }
}
class RemoteSink(name: String, port: Int) extends Actor
{
 def act() {
    println(name+" starts")
    trapExit=true
    alive(port)
    register(Symbol(name),self)

    loop {
        react {
            case Exit(from,reason) =>{
                    exit()
            }
            case msg => reply{
                    println(name+" sending reply to: "+msg)
                    msg+" back at you from "+name
                }
        }
    }
 }
}

Source.scala:

import scala.actors.Actor
import scala.actors.Actor._
import scala.actors.remote.Node;
import scala.actors.remote.RemoteActor
import scala.actors.remote.RemoteActor._

object Source {
    def main(args: Array[String]):Unit = {
        val peer = Node("127.0.0.1", 43001)
        val source = new RemoteSource(peer)
        source.start()
    }
}
class RemoteSource(peer: Node) extends Actor
{
    def act() {
        trapExit=true
        alive(43001)
        register(Symbol("source"),self)

        val sinks = List(select(peer,Symbol("node03-0"))
                                   ,select(peer,Symbol("node03-1"))
                                )
        sinks.foreach(link)

        val futures = for(sink <- sinks; i <- 0 to 20) yield    sink !! "hello "+i
        futures.foreach( f => println(f()))

        exit()
    }
}

Что я делаю не так?

Ответы [ 2 ]

2 голосов
/ 29 июля 2010

Полагаю, ваша проблема связана с этой строкой:

futures.foreach( f => println(f()))

, в котором вы перебираете все свои фьючерсы и блокируете их по очереди, ожидая его результата. Блокировка фьючерсов, как правило, плохая идея, и ее следует избегать. Вместо этого вы хотите указать действие, которое нужно выполнить , когда будет доступен будущий результат . Попробуйте это:

futures.foreach(f => f.foreach(r => println(r)))

Вот альтернативный способ сказать это для понимания:

for (future <- futures; result <- future) { println(result) }

Эта запись в блоге является отличным учебником по проблеме блокировки фьючерсов и тому, как монадические фьючерсы преодолевают ее.

0 голосов
/ 05 ноября 2014

Я видел подобный случай также. Когда код внутри потока генерирует определенные типы исключений и завершается, соответствующий файл future.get никогда не возвращается. Можно попытаться вызвать исключение java.lang.Error vs java.lang.NoSuchMethodError. Соответствующее будущее последнего никогда не вернется.

...