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
ResultMsg
vorgesehen 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
actorOf
erzeugt. 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 neuerListenerActor
erzeugt 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
ReceiveBuilders
aufgerufen, wenn eineFindMsg
eintrifft:
- Dazu wird der Inhalt der
FindMsg
analysiert:
- Für jedes Element in
filenames
wird 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 InstanzvariablennumOfChild
gespeichert:
- Dann wird für jedes Element in
filenames
eine 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
WorkerActor
gesendet (mittell
), der erst direkt zuvor erzeugt wird:
WorkerActor
- Die Methode
handleWorkMsg
muss vervollständigt werden. Das Ergebnis liegt in der lokalen Variablenresult
vor. Es muss in eine neueResultMsg
getan werden:
- Diese
ResultMsg
wird mit der Methodetell
an den Absender der hier gerade verarbeitetenWorkMsg
zurückgesendet. Dies ist derMasterActor
. DessenActorRef
kann mit der MethodegetSender
ermittelt 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
WorkerActor
eingetragen (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 inMasterActor
neu 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-NUM
WorkerActor
-Instanzen wird im Konstruktor vonMasterActor
mit einer Schleife erzeugt. Sie sollen alsArrayList
in der neuen Instanzvariablenroutee
gespeichert werden:
this.routees = new ArrayList<>();
for (var i = 0; i < MasterActor.WORKER_NUM; i++) {
var r = getContext().actorOf(Props.create(WorkerActor.class));
- Da der
MasterArctor
diese 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 TypActorRefRoutee
zu Routees aufgewertet werden:
Router
- Zum Schluss wird im Konstruktor von
MasterActor
ein Router erzeugt und in der neuen Instanzvariablerouter
gespeichert:
- 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
FindMsg
alle Teilaufgaben (hier in der lokalen Laufvariablenjob
) zu extrahieren, für jede einen neue Worker zu erzeugen und ihm denjob
mittell
zu schicken …
var findActor = getContext().actorOf(Props.create(WorkerActor.class));
findActor.tell(job, getSelf());
- … wird der
job
mit der Methoderoute
an den Router übermittelt (dessen Routees ja schon im Konstruktor desMasterActor
erzeugt 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
handleResultMsg
noch entsprechend angepasst werden. Bei jedem Eintreffen einerResultMsg
beimMasterActor
muss 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 (
numOfChild
bis 0 heruntergezählt), werden alle Worker durch jeweils eine neuePleaseCleanupAndStop
-Message heruntergefahren. Da die Worker als Routees in der Instanzvariablenroutees
zu finden sind, kann darüber iteriert werden. Da es sich hier nicht umActorRef
-Instanzen handelt (diese waren für die Speicherung inroutees
inActorRefRoutee
-Instanzen gewrappt worden, wird zum Sendensend
und nichttell
benutzt:
if (this.numOfChild == 0) {
for (var routee : this.routees) {
routee.send(new PleaseCleanupAndStop(), getSelf());
}
- Am Ende wird noch der
listener
wie bisher auch heruntergefahren:
Ändern der Aufgabe
- Dazu kann in
Main
das lokale String-Array geändert werden:
String[] files = { "test1.txt", "test2.txt", "test3.txt", "test4.txt",
"test5.txt", "test6.txt", "test7.txt", "test8.txt" };
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_NUM
5 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.