[英]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%完美的,因為如果下載時間花費的時間比預期的要長,那么您仍然可以得到更多的下載,那么可能就需要這樣做,但這是一個非常簡單的實現,我們使用它會產生很大的效果。
另一種選擇是使用下載參與者的池並刪除將來的對象,並允許參與者執行此阻止,以便他們一次只真正處理一條消息。 因為您要讓他們阻止,所以我建議給他們他們自己的Dispatcher
( ExecutionContext
),以便這種阻止不會對主要的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.