2013-12-18 7 views
5

Ich kann nicht herausfinden, warum habe ich den Fehler "deadLetters"Sender wird Schauspieler [akka: // Main/deadLetters]

class MyActor extends Actor { 

    private def getIdList = Future { blocking(getIdListSync) } 

    private def getIdListSync = { 
    val inputStreamRaw = new URL(url).openConnection.getInputStream 
    val inputStream = scala.io.Source fromInputStream inputStreamRaw 
    val json = parse(inputStream getLines() mkString "\n") 
    val jsonIds = json \ "ids" \\ classOf[JInt] 
    jsonIds take idLimit map (_.toInt) 
    } 

    def receive = { 
    case Get => 

     //doesn't work, the error is "sender" becomes "Actor[akka://Main/deadLetters]" 

//  getIdList onComplete { 
//  case Success(idList) => 
//   sender ! Result(idList) 
// 
//  case Failure(e) => // todo 
//  } 

     //works well 
     val idList = getInternalIdListSync 
     sender ! Result(idList) 

    } 
} 

Wie Sie sehen können, sender wird Actor[akka://Main/deadLetters] bei Future mit und blocking in der Methode betitelt getIdList. Warum das? Sollte ich das nicht benutzen?

Antwort

12

Das Problem ist, dass Sie sender in einem asynchronen Funktionsblock aufrufen. Es gibt eine einfache Regel dafür:

nie dicht über dem Sender-Methode in einem Codeblock, die asynchron ausgeführt werden sollen kann

sender eine Funktion ist, die den Absender der aktuell bearbeiteten Nachricht zurückgibt. Das Problem ist, dass, wenn Sie sender in einem Rückruf wie onComplete aufrufen, dieser Rückruf asynchron ausgeführt wird. Das bedeutet, dass der Akteur in der Zwischenzeit andere Nachrichten verarbeiten kann und daher die Funktion sender den Absender der ursprünglichen Nachricht möglicherweise nicht meldet.

Eine Möglichkeit, dies zu vermeiden ist es, den Absender in einer lokalen Variablen zu speichern, bevor die Ausführung asynchronen Code:

def receive = { 
    case Get => 
    val s = sender 

    // call an asynchronous function 
    myAsyncFunction onComplete{ result => 
     s ! result 
    } 
} 

Eine andere Möglichkeit ist es, die akka pipeTo Funktion zu verwenden, wie @Vadzim wies darauf hin:

import akka.pattern.pipe 

def receive = { 
    case Get => 
    // call an asynchronous function 
    val result = myAsyncFunction 

    result pipeTo sender 
} 

Weitere Informationen darüber finden Sie in der Dokumentation akka finden werden: http://doc.akka.io/docs/akka/snapshot/scala/futures.html#Use_With_Actors

+0

ist es sinnvoll, async Verfahren mit Zukunft (getIdList) zu verwenden, oder sollte ich einfach Synchronisierungsmethode (getIdListSync) verwenden? –

+0

Das hängt davon ab, was die Aufgabe des Schauspielers ist. Wenn dies die einzige Aufgabe ist, die der Aktor ausführen soll, ist die Verwendung der synchronen Variante in Ordnung. In diesem Fall sollte die Skalierung mit mehreren gleichartigen Akteuren und einem Dispatcher erfolgen. Auf der anderen Seite sollten Sie die asynchrone Variante in Betracht ziehen, wenn der Akteur während der Erstellung der Liste etwas anderes tun soll. – tmbo

+0

Aaaa, also Multithreading (und Futures) ist nur dann skalierbar, wenn es eine andere Aufgabe (oder mehr als eine Aufgabe insgesamt) gibt, an der gearbeitet wird, während die erste ausgeführt wird, richtig? –

Verwandte Themen