我有一个使用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

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

1回复

Akka演员前进消息与继续

我有一个演员从另一个演员那里获取结果并对它进行一些检查。 现在,如果我问一下Actor1,我们现在已经生成了2个期货,这看起来并不过分。 有没有办法提供某种延续的方法,或者我可以在这里使用的其他方法?
1回复

访问akka / scala中actor之外的不可变成员

我刚开始学习Akka / Scala,我写了一个小聊天服务器。 想象一下,这是一个基于房间的聊天服务器,每个人都可以创建自己的房间,可以同时在几个房间。 每当房间里的房间用完时,房间就会关闭。 房间由id: Int标识,并具有不可变的name: String 。 我写了下面的代码来介
1回复

Scala / akka模式匹配一​​系列期货流水线到演员的消息

好吧,我正在尝试创建Web请求的工作单元,并在完成后将其传递给演员。 我还不太了解匹配的问题,而且我正在试图找出一种方法来完成比赛。 我有一个与case _ : Seq[_]匹配的全能风格case _ : Seq[_]我将如何进行1)获得一个正确的案例类匹配器,在这种情况下Seq[Sub
1回复

Akka:演员交流的未来?

我有一个生成单个演员的系统,该演员将生成许多期货。 这些期货中的某些会遇到需要产生更多期货的情况(但要告诉演员有关此事)。 如何将有关未来操作完成的消息从未来发送给演员? 我查看了pipeTo文档,但是在以后的课程中无法引用系统中的参与者。 这是我的未来课程的样子: 演员
1回复

Akka actor远程解除发送延迟响应

所以我有一个基于客户端服务器的程序,客户端将向服务器发送请求,服务器将进行计算和响应。 这是通过Ask完成的。 具体来说,客户端将从客户端应用接收消息并发送呼叫请求 服务器将像这样接收它 演员集实际上是一组不同的演员。 然后,我收集结果并将其发送回发件人 我
2回复

Akka演员询问和类型安全

我如何使用Akka Actor询问并保持类型安全? 或者避免使用ask来支持tell? 打电话时? 或者在Akka Actor上ask ,返回Future[Any] ,我必须通过future.mapTo[MyType]进行显式演员。 我不喜欢失去这种类型的安全。 如果我直接使用
1回复

在akka流中使用mapFuture

我正在玩Akka Streams,并且一直在尝试对MongoDB集合中轮询的事件进行一些充实和处理。 但是,对于实现事件丰富器的最佳方法,我有些怀疑,它可能需要连接到外部数据源。 mapFuture似乎很合适,但是我遇到了一些问题: 而我的应用程序: 但是,我陷入了这个错
2回复

在Actor的receive方法中调用Multiple Future

我正在尝试在Actor的receive方法中进行两次外部调用(到Redis数据库)。 两个调用返回Future ,我需要第一的结果Future第二内侧。 我将两个调用包装在一个Redis事务中,以避免其他人在我阅读时修改数据库中的值。 actor的内部状态根据第二个Future的值进行
1回复

在receive方法中调用Future并在此之后停止actor

我正在创建一群做一些工作的演员,然后他们就被制止了。 在其中一些演员中,我正在调用返回Future第三方API。 既然Future是非阻塞的,那么演员将在那之后(?)停止,即使Future还没有完成。 在这种情况下,预期的行为是什么? 例如,如果我对Future有一个onCom
3回复

在Akka演员中使用Futures

我刚刚开始学习Scala中的Akka Actors。 我的理解是,Actor接收的消息在Actor的邮箱中排队,并且一次处理一个。 通过一次处理一个消息,可以减轻并发问题(竞争条件,死锁)。 但是如果Actor创建了一个与消息相关的工作的未来会发生什么? 由于将来是异步的,因此Act