簡體   English   中英

控制Akka actor中的消息流

[英]Control flow of messages in Akka actor

我有一個使用Akka的演員,該演員執行的操作需要一些時間才能完成,因為它必須從網絡上下載文件。

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

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

我想控制發送給該參與者的消息流。 如果我嘗試同時下載太多文件,則會遇到網絡瓶頸。 問題是我在actor的接收器內部使用了Future,所以方法退出了,actor准備處理新消息。 如果刪除“未來”,則每次只能下載一個文件。

限制每單位時間處理的消息數的最佳方法是什么? 有沒有更好的方法來設計此代碼?

有一個針對Akka的contrib項目,它提供了一個節流實現( http://letitcrash.com/post/28901663062/throttling-messages-in-akka-2 )。 如果您將它放在實際的下載角色前面,則可以有效地限制進入該角色的消息速率。 這不是100%完美的,因為如果下載時間花費的時間比預期的要長,那么您仍然可以得到更多的下載,那么可能就需要這樣做,但這是一個非常簡單的實現,我們使用它會產生很大的效果。

另一種選擇是使用下載參與者的池並刪除將來的對象,並允許參與者執行此阻止,以便他們一次只真正處理一條消息。 因為您要讓他們阻止,所以我建議給他們他們自己的DispatcherExecutionContext ),以便這種阻止不會對主要的Akka Dispatcher產生負面影響。 如果執行此操作,則池大小本身代表您允許的同時下載的最大數量。

這兩種解決方案都是非常“開箱即用”的解決方案,不需要太多自定義邏輯即可支持您的用例。

編輯

我還認為最好同時提一下“ 工作拉動模式 ”。 通過這種方法,您仍然可以使用池,然后在前面使用單個工作分配器。 每個工作人員(下載演員)都可以執行下載(仍使用Future ),並且僅在該Future完全完成(即下載完成)時才向工作發布者請求新工作(拉動)。

如果您想同時進行大量下載,則可以“確認”演員,說下載已完成,並釋放了一個位置來下載其他文件:

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緊密循環,也可以進行其他限制,具體取決於您的用例。

有消息節流的的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"

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM