Scala:等待List正在填充

时间:2013-12-16 01:49:59

标签: multithreading scala asynchronous

假设有一个List,其中存储了分布式计算的作业的结果。

现在我有一个正在等待所有工作完成的主线程。

我知道在所有工作完成之前,List的大小需要。 scala中最优雅的方式是什么让主线程(while(true)loop)在作业完成时睡眠并让它清醒?

感谢您的回答

编辑:在尝试@ Stefan-Kunze的概念后没有成功(猜测我没注意到......)我举了一些代码示例:

第一个节点:

class PingPlugin extends SmasPlugin
{
  val messages = new ListBuffer[BaseMessage]()

  val sum = 5

  def onStop = true

  def onStart =
  {
    log.info("Ping Plugin created!")

    true
  }

  def handleInit(msg: Init)
  {
    log.info("Init received")

    for( a <- 1 to sum)
    {
      msg.pingTarget ! Ping() // Ping extends BaseMessage
    }

    // block here until all messages are received
    // wait for messages.length == sum

    log.info("handleInit - messages received: %d/%d ".format(messages.length, sum))


  }

  /**
   * This method handles incoming Pong messages
   * @param msg Pong extends BaseMessage
   */
  def handlePong(msg: Pong)
  {
    log.info("Pong received from: " + msg.sender)
    messages += msg

    log.info("handlePong - messages received: %d/%d ".format(messages.length, sum))
  }
}

第二个节点:

class PongPlugin extends SmasPlugin
{
  def onStop = true

  def onStart =
  {
    log.info("Pong Plugin created!")
    true
  }

  /**
   * This method receives Ping messages and send a Pong message back after a random time
   * @param msg Ping extends BaseMessage
   */
  def handlePing(msg: Ping)
  {
    log.info("Ping received from: " + msg.sender)
    val sleep: Int = math.round(5000 * Random.nextFloat())
    log.info("sleep: " + sleep)

    Thread.sleep(sleep)
    msg.sender ! Pong()
  }
}   

我猜这个解决方案可以用期货......

2 个答案:

答案 0 :(得分:3)

挑选@jilen的方法:(此代码假设您的结果属于类型结果)

//just like lists futures can be yielded
val tasks: Seq[Future[Result]] = for (i <- 1 to results.size) yield future {
                                                   //results.size is the number of                   //results you are expecting
  println("Executing task " + i)
  Thread.sleep(i * 1000L)
  val result = ??? //your code goes here
  result
}


//merge all future results into a future of a sequence of results
val aggregated: Future[Seq[Result]] = Future.sequence(tasks)


//awaits for your results to be computed
val squares: Seq[Int] = Await.result(aggregated, Duration.Inf)
println("Squares: " + squares)

答案 1 :(得分:1)

在这里测试代码很难,因为我没有其他系统,但我会尝试。我假设所有这些都在Akka之下。

首先,像这样的阻塞表明了一个真正的设计问题。在演员系统中,您应该发送消息并继续前进。当返回正确的ping数时,您的日志命令应该在handlePong。阻止init会挂起整个actor。你真的不应该这样做。

但是,好吧,如果你绝对必须这样做呢?那么这里的一个好工具就是ask pattern。像这样的东西(我不能检查这个编译没有更多的代码):

import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.duration._

...
implicit val timeout = Timeout(5 seconds)

var pendingPongs = List.empty[Future[Pong]]

for( a <- 1 to sum)
{
  // Ask each target for Ping. Append the returned Future to pendingPongs
  pendingPongs += msg.pingTarget ? Ping() // Ping extends BaseMessage      
}

// pendingPongs is a list of futures. We want a future of a list.
// sequence() does that for us. We then block using Await until the future completes.

val pongs = Await.result(Future.sequence(pendingPongs), 5 seconds)

log.info(s"handlePong - messages received: ${pongs.length}/$sum")