[英]Akka: Cleanup of dynamically created actors necessary when they have finished?
[英]Knowing when akka actors are finished
有一些人和我一起工作,一直試圖找出處理這個問題的最佳方法。 這似乎應該是一個經常需要的標准事物,但由於某種原因,我們似乎無法得到正確的答案。
如果我有一些工作需要完成並且我在路由器上拋出一堆消息,我怎么能知道所有的工作何時完成? 例如,如果我們正在讀取100萬行文件的行並將行發送給actor來處理它,並且你需要處理下一個文件,但是必須等待第一個文件完成,你怎么知道什么時候它完成了?
還有一點評論。 我知道並且使用了與Patters.ask()一起使用的Await.result()和Await.ready()。 一個區別是,每條線都有一個未來,我們將有一個巨大的這些期貨數組等待,而不僅僅是一個。 另外,我們正在填充一個占用大量內存的大型域模型,並且不希望添加額外的內存來保存等待編寫的內存中相同數量的未來,同時使用每個人在完成工作之后完成的工作沒有等待內存等待要寫作。
我們使用的是Java而不是Scala。
偽代碼:
for(File file : files) {
...
while((String line = getNextLine(fileStream)) != null) {
router.tell(line, this.getSelf());
}
// we need to wait for this work to finish to do the next
// file because it's dependent on the previous work
}
看起來你經常想要做很多工作,並知道什么時候完成演員。
我相信我有一個解決方案,它不涉及積累一大堆Future
。 首先,高層次的概念。 將有兩名參與者參與此流程。 第一個我們將調用FilesProcessor
。 這個演員將是短暫的和有狀態的。 每當您想要按順序處理一堆文件時,您就會啟動此actor的實例並向其傳遞一條消息,其中包含您要處理的文件的名稱(或路徑)。 當它完成所有文件的處理后,它會自行停止。 我們將調用LineProcessor
的第二個actor。 這個演員是無國籍的,長壽,匯集在路由器后面。 它處理文件行,然后回復請求行處理的任何人,告訴他們已完成處理該行。 現在進入代碼。
首先是消息:
public class Messages {
public static class ProcessFiles{
public final List<String> fileNames;
public ProcessFiles(List<String> fileNames){
this.fileNames = fileNames;
}
}
public static class ProcessLine{
public final String line;
public ProcessLine(String line){
this.line = line;
}
}
public static class LineProcessed{}
public static LineProcessed LINE_PROCESSED = new LineProcessed();
}
和FilesProcessor
:
public class FilesProcessor extends UntypedActor{
private List<String> files;
private int awaitingCount;
private ActorRef router;
@Override
public void onReceive(Object msg) throws Exception {
if (msg instanceof ProcessFiles){
ProcessFiles pf = (ProcessFiles)msg;
router = ... //lookup router;
files = pf.fileNames;
processNextFile();
}
else if (msg instanceof LineProcessed){
awaitingCount--;
if (awaitingCount <= 0){
processNextFile();
}
}
}
private void processNextFile(){
if (files.isEmpty()) getContext().stop(getSelf());
else{
String file = files.remove(0);
BufferedReader in = openFile(file);
String input = null;
awaitingCount = 0;
try{
while((input = in.readLine()) != null){
router.tell(new Messages.ProcessLine(input), getSelf());
awaitingCount++;
}
}
catch(IOException e){
e.printStackTrace();
getContext().stop(getSelf());
}
}
}
private BufferedReader openFile(String name){
//do whetever to load file
...
}
}
而LineProcessor
:
public class LineProcessor extends UntypedActor{
@Override
public void onReceive(Object msg) throws Exception {
if (msg instanceof ProcessLine){
ProcessLine pl = (ProcessLine)msg;
//Do whatever line processing...
getSender().tell(Messages.LINE_PROCESSED, getSelf());
}
}
}
現在,線路處理器正在發送回復而沒有其他內容。 如果你需要根據線路的處理發回一些東西,你當然可以改變它。 我確信這段代碼不是防彈,我只想向您展示一個高級概念,說明如何在沒有請求/響應語義和Future
的情況下完成此流程。
如果您對此方法有任何疑問或想了解更多細節,請告訴我,我很樂意提供。
在路由上使用context.setRecieveTimeout
將消息發送回發送方,並計算已處理的消息數。 當處理的郵件總數==發送的金額完成后。
如果您的路由足夠繁忙, setReceiveTimeout
將不會經常觸發,那么請安排自己的消息以重新發送計數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.