在Scala中查询其当前状态/值的连续运行操作

时间:2013-11-07 03:01:04

标签: scala akka

我有一个持续更新值的过程。我希望能够定期查询当前值的操作。在我的特定示例中,每个更新都可以被视为一种改进,并且该过程最终将收敛于最终的最佳答案,但我希望/需要访问中间结果。循环执行的速度和收敛所需的时间很重要。

举个例子,考虑一下这个循环:

var current = 0
while(current < 100){
  current = current + 1
}

我希望能够在任何循环迭代中获得当前值。

与Actor的解决方案是:

class UpdatingActor extends Actor{
  var current : Int = 0
  def receive = {
    case Update => {
      current = current + 1
      if (current < 100) self ! Update
    }
    case Query => sender ! current
  }
}

你可以使用become或FSM摆脱var,但这个例子更清楚IMO。

或者,一个actor可以运行该操作并将每次循环迭代的更新结果发送给另一个actor,该actor唯一的职责是更新值并响应有关它的查询。我对Akka中的“代理人”了解不多,但这似乎是一个潜在的用例。

使用Scala执行此操作的更好/替代方法是什么?我不需要使用演员;这只是一个想到的解决方案。

2 个答案:

答案 0 :(得分:1)

你的基于演员的解决方案还可以。

如果计算长时间阻止演员并且您想确保始终获得中间结果,那么在每次更改后将中间结果发送到“结果提供者”演员也是一个好主意。另一种选择是使实际的计算器演员成为收集最佳结果的演员的孩子。这样,事物就会从外部充当单个actor,并且你有一个actor,它具有与执行计算的actor分开的状态(当前最佳结果),这可能会失败。

agent在非常低级 @ volatile / AtomicInteger 方法与Actor之间有一定的解决方案。代理只能通过对其进行转换来修改(并且存在转换队列),但具有始终可以访问的当前状态。虽然它不是位置透明的。如果你需要的话,请继续使用演员的方法。

以下是使用代理解决此问题的方法。你有一个线程执行长时间运行的计算(由Thread.sleep模拟)和另一个线程,它只是以固定间隔打印出最佳当前结果(也由Thread.sleep模拟)。

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
import scala.concurrent._
import akka.agent.Agent

object Main extends App {
  val agent = Agent(0)

  def computation() : Unit = {
    for(i<-0 until 100) {
      agent.send { current => 
        Thread.sleep(1000) // to simulate a long-running computation
        current + 1
      }
    }
  }

  def watch() : Unit = {
    while(true) {
      println("Current value is " + agent.get)
      Thread.sleep(1000)
    }
  }

  global.execute(new Runnable {
    def run() = computation
  })
  watch()
}

但总而言之,我认为基于演员的解决方案会更优越。例如,您可以在与结果跟踪不同的机器上进行计算。

答案 1 :(得分:0)

问题的范围有点宽,但我会尝试:)

首先,你的例子非常好,我没有看到摆脱var的意义。这就是演员的目的:保护可变状态。

其次,根据你描述的内容,你根本不需要演员。

class UpdatingActor {
  private var current = 0
  def startCrazyJob() {
    while(current < 100){
      current = current + 1
    }
  }

  def soWhatsGoingOn: Int = current 
}

您只需要一个帖子就可以拨打startCrazyJob,第二个线程会定期拨打soWhatsGoingOn

恕我直言,演员方法更好,但是由你来决定是否值得为这个用例导入akka库。