我有一个使用Akka的演员,该演员执行的操作需要一些时间才能完成,因为它必须从网络上下载文件。

  def receive = {
    case songId: String => {
      Future {
        val futureFile = downloadFile(songId)

        for (file <- futureFile) {
          val fileName = doSomenthingWith(file)
          otherActor ! fileName
        }
      }
    }
  }

我想控制发送给该参与者的消息流。 如果我尝试同时下载太多文件,则会遇到网络瓶颈。 问题是我在actor的接收器内部使用了Future,所以方法退出了,actor准备处理新消息。 如果删除“未来”,则每次只能下载一个文件。

限制每单位时间处理的消息数的最佳方法是什么? 有没有更好的方法来设计此代码?

===============>>#1 票数:3

有一个针对Akka的contrib项目,它提供了一个节流实现( http://letitcrash.com/post/28901663062/throttling-messages-in-akka-2 )。 如果您将它放在实际的下载角色前面,则可以有效地限制进入该角色的消息速率。 这不是100%完美的,因为如果下载时间花费的时间比预期的要长,那么您仍然可以得到更多的下载,那么可能就需要这样做,但这是一个非常简单的实现,我们使用它会产生很大的效果。

另一种选择是使用下载参与者的池并删除将来的对象,并允许参与者执行此阻止,以便他们一次只真正处理一条消息。 因为您要让他们阻止,所以我建议给他们他们自己的DispatcherExecutionContext ),以便这种阻止不会对主要的Akka Dispatcher产生负面影响。 如果执行此操作,则池大小本身代表您允许的同时下载的最大数量。

这两种解决方案都是非常“开箱即用”的解决方案,不需要太多自定义逻辑即可支持您的用例。

编辑

我还认为最好同时提一下“ 工作拉动模式 ”。 通过这种方法,您仍然可以使用池,然后在前面使用单个工作分配器。 每个工作人员(下载演员)都可以执行下载(仍使用Future ),并且仅在该Future完全完成(即下载完成)时才向工作发布者请求新工作(拉动)。

===============>>#2 票数:0

如果您想同时进行大量下载,则可以“确认”演员,说下载已完成,并释放了一个位置来下载其他文件:

case object AckFileRequest

class ActorExample(otherActor:ActorRef, maxFileRequests:Int = 1) extends Actor {

  var fileRequests = 0

  def receive = {
    case songId: String if fileRequests < maxFileRequests =>
      fileRequests += 1
      val thisActor = self
      Future {
        val futureFile = downloadFile(songId)
        //not sure if you're returning the downloaded file or a future here, 
        //but you can move this to wherever the downloaded file is and ack
        thisActor ! AckFileRequest

        for (file <- futureFile) {
          val fileName = doSomenthingWith(file)
          otherActor ! fileName
        }
      }
    case songId: String =>
      //Do some throttling here
      val thisActor = self
      context.system.scheduler.scheduleOnce(1 second, thisActor, songId)
    case AckFileRequest => fileRequests -= 1
  }
}

在此示例中,如果文件请求太多,则将这个songId请求置于保留状态,并将其排队等待1秒后再处理。 您显然可以更改此设置,但是您认为合适,也许您可​​以将消息直接发送给actor紧密循环,也可以进行其他限制,具体取决于您的用例。

===============>>#3 票数:0 已采纳

有消息节流的的contrib实施, 这里描述

代码很简单:

// A simple actor that prints whatever it receives
class Printer extends Actor {
  def receive = {
    case x => println(x)
  }
}

val printer = system.actorOf(Props[Printer], "printer")

// The throttler for this example, setting the rate
val throttler = system.actorOf(Props(classOf[TimerBasedThrottler], 3 msgsPer 1.second))

// Set the target
throttler ! SetTarget(Some(printer))
// These three messages will be sent to the printer immediately
throttler ! "1"
throttler ! "2"
throttler ! "3"
// These two will wait at least until 1 second has passed
throttler ! "4"
throttler ! "5"

  ask by Daniel Cukier translate from so

未解决问题?本站智能推荐: