Musterlösungen
Laboraufgabe “Paralleles Suchen/Finden eines Suchstrings in einigen wenigen Textdateien”
neue Klasse ListenerActor
- Die Signatur der Methode ist in der Aufgabe spezifiziert:
- Dies bedingt, dass die folgende Methode implementiert wird:
- In dieser Methode muss ein “Match” für Objekte des Typs
ResultMsgvorgesehen werden:
- Falls solch ein Objekt empfangen wird, muss sein Inhalt ausgegeben werden und das Akka-System terminiert werden (als Lambda-Ausdruck formuliert):
Konstruktor von MasterActor
- Ein neuer Actor wird mit der Methode
actorOferzeugt. Er wird in die Hierarchie der Aktoren dadurch einsortiert, dass diese Methode im übergeordneten Kontext erzeugt wird. Das ist hier der Kontext derMasterActor-Instanz. Dieser Kontext wird durchgetContext()vonthis(einemMasterActor) geholt.
- Die
actorOf-Methode bekomt hier zwei Parameter: Erstens eine Spezifikation des neuen Actors. Hier soll ein neuerListenerActorerzeugt werden. Das komplexeProps-Framework ist ebenso wie Akka eine Entwicklung der Firma Lightbend. Nehmen Sie es hier einfach als idomatischen Gebrauch hin. Eine genauere Erklärung würde hier zu weit gehen:
- Der zweite Parameter für die
actorOf-Methode ist ein symbolischer Name für den Actor, der ggf. auch zur Identifikation (anstatt desActorRef-Handles) herangezogen werden kann. Er wird alsStringübergeben:
FindMsg mit MasterActor verarbeiten
- Dazu muss die folgende Methode ausformuliert werden. Sie wird aufgrund des
ReceiveBuildersaufgerufen, wenn eineFindMsgeintrifft:
- Dazu wird der Inhalt der
FindMsganalysiert:
- Für jedes Element in
filenameswird eine neue Nachricht erzeugt, die von Workern bearbeitet wird. Es ergibt sich für jede dieser Anfragen eine Antwort. Damit im laufenden Betrieb die Anzahl der jeweils noch zu erwartenden Antworten mitprotokolliert werden kann, wird die anfängliche Anzahl in der InstanzvariablennumOfChildgespeichert:
- Dann wird für jedes Element in
filenameseine neue Nachricht erzeugt, die das zu lösende Teilproblem enthält:
- Jede dieser so erzeugten Nachrichten wird an einen jeweils neu und nur für diese Nachricht zuständigen
WorkerActorgesendet (mittell), der erst direkt zuvor erzeugt wird:
WorkerActor
- Die Methode
handleWorkMsgmuss vervollständigt werden. Das Ergebnis liegt in der lokalen Variablenresultvor. Es muss in eine neueResultMsggetan werden:
- Diese
ResultMsgwird mit der Methodetellan den Absender der hier gerade verarbeitetenWorkMsgzurückgesendet. Dies ist derMasterActor. DessenActorRefkann mit der MethodegetSenderermittelt werden. Das Akka-Framework sorgt dafür, dass dabei der Absender der Nachricht, die gerade verarbeitet wird, ermittelt wird.
- Als Absender dieser Nachricht wird der gerade arbeitende
WorkerActoreingetragen (2. Parameter vontell), der mit der folgenden Methode ermittelt wird:
Laboraufgabe “Paralleles Suchen/Finden eines Suchstrings in sehr vielen Textdateien mit einem Router”
neue Instanzvariablen für MasterActor
- Die folgenden nicht veränderliches (
final) privaten Instanzvariablen werden inMasterActorneu eingeführt:
- Die Anzahl der zu erzeugenden
Routee-Instanzen wird durch eine Konstante spezifiziert. Im Beispiel erhält Sie den Wert 5:
Routees erzeugen
- Die Anzahl von
WORKER-NUMWorkerActor-Instanzen wird im Konstruktor vonMasterActormit einer Schleife erzeugt. Sie sollen alsArrayListin der neuen Instanzvariablenrouteegespeichert werden:
- Da der
MasterArctordiese Routees erzeugt, soll er sie auch (in seinem Kontext) im Sinne des Error Kernel Design Patterns überwachen:
- Die
WorkerActor-Instanzen müssen über einen Wrapper vom TypActorRefRouteezu Routees aufgewertet werden:
Router
- Zum Schluss wird im Konstruktor von
MasterActorein Router erzeugt und in der neuen Instanzvariableroutergespeichert:
- Die Parameter sind eine Spezifikation des Routing-Verhaltens (hier Round-Robin) und die Liste der vom Router zu bedienenden Routees:
Einbinden des Routers
- Statt wie bisher beim Eintreffen von
FindMsgalle Teilaufgaben (hier in der lokalen Laufvariablenjob) zu extrahieren, für jede einen neue Worker zu erzeugen und ihm denjobmittellzu schicken …
- … wird der
jobmit der Methoderoutean den Router übermittelt (dessen Routees ja schon im Konstruktor desMasterActorerzeugt und dem Router mitgeteilt wurden:
- Da die Worker nun nicht mehr nach ihrer (Erst-) Benutzung gelöscht werden dürfen (sie bleiben ja als Routee im Verantwortungsbereich des Routers), muss
handleResultMsgnoch entsprechend angepasst werden. Bei jedem Eintreffen einerResultMsgbeimMasterActormuss die Anzahl der noch erwarteten Nachrichten um 1 heruntergezählt werden:
- Das empfangene Teilergebnis muss nach wie vor in das Gesamtergebnis integriert werden:
- Erst wenn keine Antworten mehr zu erwarten sind (
numOfChildbis 0 heruntergezählt), werden alle Worker durch jeweils eine neuePleaseCleanupAndStop-Message heruntergefahren. Da die Worker als Routees in der Instanzvariablenrouteeszu finden sind, kann darüber iteriert werden. Da es sich hier nicht umActorRef-Instanzen handelt (diese waren für die Speicherung inrouteesinActorRefRoutee-Instanzen gewrappt worden, wird zum Sendensendund nichttellbenutzt:
- Am Ende wird noch der
listenerwie bisher auch heruntergefahren:
Ändern der Aufgabe
- Dazu kann in
Maindas lokale String-Array geändert werden:
Die neuen Dateien müssen in das Wurzelverzeichnis des Projekts kopiert werden, denn das ist in diesem Projekt das Arbeitsverzeichnis.
Im Beispiel hier ist
WORKER_NUM5 und die Anzahl der zu durchsuchenden Dateien 8. Mindestens 3WorkMsg-Nachrichten müssen also von Routees verarbeitet werden, die mehr als eine Nachricht bekommen haben.