forked from Parallele_Programmierung/Labs
Kap. 4: Actors/Akka
parent
3e16aa8f36
commit
480a9f985c
|
|
@ -0,0 +1,7 @@
|
|||
# Laboraufgabe "Paralleles Suchen/Finden eines Suchstrings in einigen wenigen Textdateien"
|
||||
- [Aufgabenstellung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/11-01-FindWords.html)
|
||||
- [Musterlösung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/11-Solutions.html#laboraufgabe-paralleles-suchenfinden-eines-suchstrings-in-einigen-wenigen-textdateien)
|
||||
|
||||
# Materialien
|
||||
- [Folien](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/slides/11-actors.html)
|
||||
- [Skript](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/notes/11-actors.html)
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# Justfile (https://just.systems/) for starting Maven standard targets
|
||||
|
||||
default:
|
||||
just exec pp.Main ""
|
||||
|
||||
exec class args: compile
|
||||
mvn exec:java -Dexec.args="{{args}}" -Dexec.mainClass={{class}}
|
||||
clean:
|
||||
mvn clean
|
||||
compile:
|
||||
mvn compile
|
||||
test: compile
|
||||
mvn test
|
||||
javadoc:
|
||||
mvn javadoc:javadoc
|
||||
package:
|
||||
mvn package
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>pp</groupId>
|
||||
<artifactId>pp.11.01-FindWords</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
<properties>
|
||||
<exec.mainClass>pp.Main</exec.mainClass>
|
||||
<maven.compiler.release>16</maven.compiler.release>
|
||||
<lombok.version>edge-SNAPSHOT</lombok.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.typesafe.akka</groupId>
|
||||
<artifactId>akka-actor_3</artifactId>
|
||||
<version>2.8.5</version>
|
||||
</dependency>
|
||||
<dependency><!-- für Unit-Tests -->
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>5.10.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency><!-- für Lombok -->
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency><!-- für net.jcip Annotationen -->
|
||||
<groupId>net.jcip</groupId>
|
||||
<artifactId>jcip-annotations</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<defaultGoal>clean compile exec:java</defaultGoal>
|
||||
<plugins>
|
||||
<plugin><!-- für Unit-Tests [mvn test] -->
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
</plugin>
|
||||
<plugin><!-- [mvn compile] -->
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.9.0</version>
|
||||
<configuration>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin><!-- [mvn exec:java] -->
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</plugin>
|
||||
<plugin><!-- [mvn javadoc:javadoc] -->
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.5.0</version>
|
||||
<configuration>
|
||||
<show>private</show>
|
||||
<locale>en_US</locale>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
package pp;
|
||||
|
||||
public class ListenerActor {
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package pp;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.actor.Props;
|
||||
import pp.messages.FindMsg;
|
||||
|
||||
public class Main {
|
||||
|
||||
public static void main(String... args) {
|
||||
var system = ActorSystem.create();
|
||||
var master = system.actorOf(Props.create(MasterActor.class));
|
||||
String[] files = { "src/main/resources/test1.txt", "src/main/resources/test2.txt", "src/main/resources/test3.txt", "src/main/resources/test4.txt" };
|
||||
var msg = new FindMsg(Arrays.asList(files), "Erlang");
|
||||
master.tell(msg, ActorRef.noSender());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package pp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.actor.ActorRef;
|
||||
import pp.messages.FindMsg;
|
||||
import pp.messages.PleaseCleanupAndStop;
|
||||
import pp.messages.ResultMsg;
|
||||
|
||||
public class MasterActor extends AbstractActor {
|
||||
private int numOfChild;
|
||||
private final List<String> result = new ArrayList<>();
|
||||
private ActorRef listener;
|
||||
|
||||
public MasterActor() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder() //
|
||||
.match(FindMsg.class, this::handleFindMsg) //
|
||||
.match(ResultMsg.class, this::handleResultMsg) //
|
||||
.build();
|
||||
}
|
||||
|
||||
private void handleFindMsg(FindMsg msg) {
|
||||
// TODO ausformulieren
|
||||
}
|
||||
|
||||
private void handleResultMsg(ResultMsg msg) {
|
||||
getSender().tell(new PleaseCleanupAndStop(), getSelf());
|
||||
this.numOfChild--;
|
||||
this.result.addAll(msg.result());
|
||||
if (this.numOfChild == 0) {
|
||||
this.listener.tell(new ResultMsg(this.result), getSelf());
|
||||
getContext().stop(getSelf());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package pp;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import akka.actor.AbstractActor;
|
||||
import pp.messages.PleaseCleanupAndStop;
|
||||
import pp.messages.ResultMsg;
|
||||
import pp.messages.WorkMsg;
|
||||
|
||||
public class WorkerActor extends AbstractActor {
|
||||
private Path path;
|
||||
private Pattern searchPattern;
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder() //
|
||||
.match(WorkMsg.class, this::handleWorkMsg) //
|
||||
.match(PleaseCleanupAndStop.class,
|
||||
(m) -> getContext().stop(getSelf())) //
|
||||
.build();
|
||||
}
|
||||
|
||||
private void handleWorkMsg(WorkMsg msg) throws IOException {
|
||||
this.path = Paths.get(msg.filename());
|
||||
this.searchPattern = Pattern
|
||||
.compile(".*\\b" + msg.searchword() + "\\b.*");
|
||||
var result = new ArrayList<String>();
|
||||
var lines = Files.readAllLines(this.path, StandardCharsets.UTF_8);
|
||||
var count = 0;
|
||||
for (var line : lines) {
|
||||
count++;
|
||||
if (this.searchPattern.matcher(line).matches()) {
|
||||
result.add(this.path + " " + count + " : " + line);
|
||||
}
|
||||
}
|
||||
// TODO: Resultat (result) an den MasterActor (Absender der WorkMsg msg)
|
||||
// zurücksenden
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package pp.messages;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record FindMsg(List<String> filenames, String searchword) {
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
package pp.messages;
|
||||
|
||||
public record PleaseCleanupAndStop() {
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package pp.messages;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record ResultMsg(List<String> result) {
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
package pp.messages;
|
||||
|
||||
public record WorkMsg(String filename, String searchword) {
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# Laboraufgabe "Paralleles Suchen/Finden eines Suchstrings in einigen wenigen Textdateien"
|
||||
- [Aufgabenstellung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/11-01-FindWords.html)
|
||||
- [Musterlösung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/11-Solutions.html#laboraufgabe-paralleles-suchenfinden-eines-suchstrings-in-einigen-wenigen-textdateien)
|
||||
|
||||
# Materialien
|
||||
- [Folien](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/slides/11-actors.html)
|
||||
- [Skript](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/notes/11-actors.html)
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# Justfile (https://just.systems/) for starting Maven standard targets
|
||||
|
||||
default:
|
||||
just exec pp.Main ""
|
||||
|
||||
exec class args: compile
|
||||
mvn exec:java -Dexec.args="{{args}}" -Dexec.mainClass={{class}}
|
||||
clean:
|
||||
mvn clean
|
||||
compile:
|
||||
mvn compile
|
||||
test: compile
|
||||
mvn test
|
||||
javadoc:
|
||||
mvn javadoc:javadoc
|
||||
package:
|
||||
mvn package
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>pp</groupId>
|
||||
<artifactId>pp.11.01-FindWords_solution</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
<properties>
|
||||
<exec.mainClass>pp.Main</exec.mainClass>
|
||||
<maven.compiler.release>16</maven.compiler.release>
|
||||
<lombok.version>edge-SNAPSHOT</lombok.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.typesafe.akka</groupId>
|
||||
<artifactId>akka-actor_3</artifactId>
|
||||
<version>2.8.5</version>
|
||||
</dependency>
|
||||
<dependency><!-- für Unit-Tests -->
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>5.10.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency><!-- für Lombok -->
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency><!-- für net.jcip Annotationen -->
|
||||
<groupId>net.jcip</groupId>
|
||||
<artifactId>jcip-annotations</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<defaultGoal>clean compile exec:java</defaultGoal>
|
||||
<plugins>
|
||||
<plugin><!-- für Unit-Tests [mvn test] -->
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
</plugin>
|
||||
<plugin><!-- [mvn compile] -->
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.9.0</version>
|
||||
<configuration>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin><!-- [mvn exec:java] -->
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</plugin>
|
||||
<plugin><!-- [mvn javadoc:javadoc] -->
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.5.0</version>
|
||||
<configuration>
|
||||
<show>private</show>
|
||||
<locale>en_US</locale>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package pp;
|
||||
|
||||
import akka.actor.AbstractActor;
|
||||
import pp.messages.ResultMsg;
|
||||
|
||||
public class ListenerActor extends AbstractActor {
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder() //
|
||||
.match(ResultMsg.class, (msg) -> {
|
||||
msg.result().forEach(System.out::println);
|
||||
getContext().getSystem().terminate();
|
||||
}).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package pp;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.actor.Props;
|
||||
import pp.messages.FindMsg;
|
||||
|
||||
public class Main {
|
||||
|
||||
public static void main(String... args) {
|
||||
var system = ActorSystem.create();
|
||||
var master = system.actorOf(Props.create(MasterActor.class));
|
||||
String[] files = { "src/main/resources/test1.txt", "src/main/resources/test2.txt", "src/main/resources/test3.txt", "src/main/resources/test4.txt" };
|
||||
var msg = new FindMsg(Arrays.asList(files), "Erlang");
|
||||
master.tell(msg, ActorRef.noSender());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
package pp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.Props;
|
||||
import pp.messages.FindMsg;
|
||||
import pp.messages.PleaseCleanupAndStop;
|
||||
import pp.messages.ResultMsg;
|
||||
import pp.messages.WorkMsg;
|
||||
|
||||
public class MasterActor extends AbstractActor {
|
||||
private int numOfChild;
|
||||
private final List<String> result = new ArrayList<>();
|
||||
private final ActorRef listener;
|
||||
|
||||
public MasterActor() {
|
||||
this.listener = getContext().actorOf(Props.create(ListenerActor.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder() //
|
||||
.match(FindMsg.class, this::handleFindMsg) //
|
||||
.match(ResultMsg.class, this::handleResultMsg) //
|
||||
.build();
|
||||
}
|
||||
|
||||
private void handleFindMsg(FindMsg msg) {
|
||||
var filenames = msg.filenames();
|
||||
var searchword = msg.searchword();
|
||||
this.numOfChild = msg.filenames().size();
|
||||
for (var filename : filenames) {
|
||||
var job = new WorkMsg(filename, searchword);
|
||||
var findActor = getContext()
|
||||
.actorOf(Props.create(WorkerActor.class));
|
||||
findActor.tell(job, getSelf());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void handleResultMsg(ResultMsg msg) {
|
||||
getSender().tell(new PleaseCleanupAndStop(), getSelf());
|
||||
this.numOfChild--;
|
||||
this.result.addAll(msg.result());
|
||||
if (this.numOfChild == 0) {
|
||||
this.listener.tell(new ResultMsg(this.result), getSelf());
|
||||
getContext().stop(getSelf());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package pp;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import akka.actor.AbstractActor;
|
||||
import pp.messages.PleaseCleanupAndStop;
|
||||
import pp.messages.ResultMsg;
|
||||
import pp.messages.WorkMsg;
|
||||
|
||||
public class WorkerActor extends AbstractActor {
|
||||
private Path path;
|
||||
private Pattern searchPattern;
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder() //
|
||||
.match(WorkMsg.class, this::handleWorkMsg) //
|
||||
.match(PleaseCleanupAndStop.class,
|
||||
(m) -> getContext().stop(getSelf())) //
|
||||
.build();
|
||||
}
|
||||
|
||||
private void handleWorkMsg(WorkMsg msg) throws IOException {
|
||||
this.path = Paths.get(msg.filename());
|
||||
this.searchPattern = Pattern
|
||||
.compile(".*\\b" + msg.searchword() + "\\b.*");
|
||||
var result = new ArrayList<String>();
|
||||
var lines = Files.readAllLines(this.path, StandardCharsets.UTF_8);
|
||||
var count = 0;
|
||||
for (var line : lines) {
|
||||
count++;
|
||||
if (this.searchPattern.matcher(line).matches()) {
|
||||
result.add(this.path + " " + count + " : " + line);
|
||||
}
|
||||
}
|
||||
getSender().tell(new ResultMsg(result), getSelf());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package pp.messages;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record FindMsg(List<String> filenames, String searchword) {
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
package pp.messages;
|
||||
|
||||
public record PleaseCleanupAndStop() {
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package pp.messages;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record ResultMsg(List<String> result) {
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
package pp.messages;
|
||||
|
||||
public record WorkMsg(String filename, String searchword) {
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# Laboraufgabe "Paralleles Suchen/Finden eines Suchstrings in sehr vielen Textdateien mit einem Router"
|
||||
- [Aufgabenstellung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/11-02-RouterFindWords.html)
|
||||
- [Musterlösung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/11-Solutions.html#laboraufgabe-paralleles-suchenfinden-eines-suchstrings-in-sehr-vielen-textdateien-mit-einem-router)
|
||||
|
||||
# Materialien
|
||||
- [Folien](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/slides/11-actors.html)
|
||||
- [Skript](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/notes/11-actors.html)
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# Justfile (https://just.systems/) for starting Maven standard targets
|
||||
|
||||
default:
|
||||
just exec pp.Main ""
|
||||
|
||||
exec class args: compile
|
||||
mvn exec:java -Dexec.args="{{args}}" -Dexec.mainClass={{class}}
|
||||
clean:
|
||||
mvn clean
|
||||
compile:
|
||||
mvn compile
|
||||
test: compile
|
||||
mvn test
|
||||
javadoc:
|
||||
mvn javadoc:javadoc
|
||||
package:
|
||||
mvn package
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>pp</groupId>
|
||||
<artifactId>pp.11.02-RouterFindWords</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
<properties>
|
||||
<exec.mainClass>pp.Main</exec.mainClass>
|
||||
<maven.compiler.release>16</maven.compiler.release>
|
||||
<lombok.version>edge-SNAPSHOT</lombok.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.typesafe.akka</groupId>
|
||||
<artifactId>akka-actor_3</artifactId>
|
||||
<version>2.8.5</version>
|
||||
</dependency>
|
||||
<dependency><!-- für Unit-Tests -->
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>5.10.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency><!-- für Lombok -->
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency><!-- für net.jcip Annotationen -->
|
||||
<groupId>net.jcip</groupId>
|
||||
<artifactId>jcip-annotations</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<defaultGoal>clean compile exec:java</defaultGoal>
|
||||
<plugins>
|
||||
<plugin><!-- für Unit-Tests [mvn test] -->
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
</plugin>
|
||||
<plugin><!-- [mvn compile] -->
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.9.0</version>
|
||||
<configuration>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin><!-- [mvn exec:java] -->
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</plugin>
|
||||
<plugin><!-- [mvn javadoc:javadoc] -->
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.5.0</version>
|
||||
<configuration>
|
||||
<show>private</show>
|
||||
<locale>en_US</locale>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package pp;
|
||||
|
||||
import akka.actor.AbstractActor;
|
||||
import pp.messages.ResultMsg;
|
||||
|
||||
public class ListenerActor extends AbstractActor {
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder() //
|
||||
.match(ResultMsg.class, (msg) -> {
|
||||
msg.result().forEach(System.out::println);
|
||||
getContext().getSystem().terminate();
|
||||
}).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package pp;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.actor.Props;
|
||||
import pp.messages.FindMsg;
|
||||
|
||||
public class Main {
|
||||
|
||||
public static void main(String... args) {
|
||||
var system = ActorSystem.create();
|
||||
var master = system.actorOf(Props.create(MasterActor.class));
|
||||
String[] files = { "src/main/resources/test1.txt", "src/main/resources/test2.txt", "src/main/resources/test3.txt",
|
||||
"src/main/resources/test4.txt",
|
||||
"src/main/resources/test5.txt", "src/main/resources/test6.txt", "src/main/resources/test7.txt",
|
||||
"src/main/resources/test8.txt" };
|
||||
var msg = new FindMsg(Arrays.asList(files), "Erlang");
|
||||
master.tell(msg, ActorRef.noSender());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
package pp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.Props;
|
||||
import pp.messages.FindMsg;
|
||||
import pp.messages.PleaseCleanupAndStop;
|
||||
import pp.messages.ResultMsg;
|
||||
import pp.messages.WorkMsg;
|
||||
|
||||
public class MasterActor extends AbstractActor {
|
||||
private int numOfChild;
|
||||
private final List<String> result = new ArrayList<>();
|
||||
private final ActorRef listener;
|
||||
|
||||
public MasterActor() {
|
||||
this.listener = getContext().actorOf(Props.create(ListenerActor.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder() //
|
||||
.match(FindMsg.class, this::handleFindMsg) //
|
||||
.match(ResultMsg.class, this::handleResultMsg) //
|
||||
.build();
|
||||
}
|
||||
|
||||
private void handleFindMsg(FindMsg msg) {
|
||||
var filenames = msg.filenames();
|
||||
var searchword = msg.searchword();
|
||||
this.numOfChild = msg.filenames().size();
|
||||
for (var filename : filenames) {
|
||||
var job = new WorkMsg(filename, searchword);
|
||||
var findActor = getContext()
|
||||
.actorOf(Props.create(WorkerActor.class));
|
||||
findActor.tell(job, getSelf());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void handleResultMsg(ResultMsg msg) {
|
||||
getSender().tell(new PleaseCleanupAndStop(), getSelf());
|
||||
this.numOfChild--;
|
||||
this.result.addAll(msg.result());
|
||||
if (this.numOfChild == 0) {
|
||||
this.listener.tell(new ResultMsg(this.result), getSelf());
|
||||
getContext().stop(getSelf());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package pp;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import akka.actor.AbstractActor;
|
||||
import pp.messages.PleaseCleanupAndStop;
|
||||
import pp.messages.ResultMsg;
|
||||
import pp.messages.WorkMsg;
|
||||
|
||||
public class WorkerActor extends AbstractActor {
|
||||
private Path path;
|
||||
private Pattern searchPattern;
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder() //
|
||||
.match(WorkMsg.class, this::handleWorkMsg) //
|
||||
.match(PleaseCleanupAndStop.class,
|
||||
(m) -> getContext().stop(getSelf())) //
|
||||
.build();
|
||||
}
|
||||
|
||||
private void handleWorkMsg(WorkMsg msg) throws IOException {
|
||||
this.path = Paths.get(msg.filename());
|
||||
this.searchPattern = Pattern
|
||||
.compile(".*\\b" + msg.searchword() + "\\b.*");
|
||||
var result = new ArrayList<String>();
|
||||
var lines = Files.readAllLines(this.path, StandardCharsets.UTF_8);
|
||||
var count = 0;
|
||||
for (var line : lines) {
|
||||
count++;
|
||||
if (this.searchPattern.matcher(line).matches()) {
|
||||
result.add(this.path + " " + count + " : " + line);
|
||||
}
|
||||
}
|
||||
getSender().tell(new ResultMsg(result), getSelf());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package pp.messages;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record FindMsg(List<String> filenames, String searchword) {
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
package pp.messages;
|
||||
|
||||
public record PleaseCleanupAndStop() {
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package pp.messages;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record ResultMsg(List<String> result) {
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
package pp.messages;
|
||||
|
||||
public record WorkMsg(String filename, String searchword) {
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# Laboraufgabe "Paralleles Suchen/Finden eines Suchstrings in sehr vielen Textdateien mit einem Router"
|
||||
- [Aufgabenstellung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/11-02-RouterFindWords.html)
|
||||
- [Musterlösung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/11-Solutions.html#laboraufgabe-paralleles-suchenfinden-eines-suchstrings-in-sehr-vielen-textdateien-mit-einem-router)
|
||||
|
||||
# Materialien
|
||||
- [Folien](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/slides/11-actors.html)
|
||||
- [Skript](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/notes/11-actors.html)
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# Justfile (https://just.systems/) for starting Maven standard targets
|
||||
|
||||
default:
|
||||
just exec pp.Main ""
|
||||
|
||||
exec class args: compile
|
||||
mvn exec:java -Dexec.args="{{args}}" -Dexec.mainClass={{class}}
|
||||
clean:
|
||||
mvn clean
|
||||
compile:
|
||||
mvn compile
|
||||
test: compile
|
||||
mvn test
|
||||
javadoc:
|
||||
mvn javadoc:javadoc
|
||||
package:
|
||||
mvn package
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>pp</groupId>
|
||||
<artifactId>pp.11.02-RouterFindWords_solution</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
<properties>
|
||||
<exec.mainClass>pp.Main</exec.mainClass>
|
||||
<maven.compiler.release>16</maven.compiler.release>
|
||||
<lombok.version>edge-SNAPSHOT</lombok.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.typesafe.akka</groupId>
|
||||
<artifactId>akka-actor_3</artifactId>
|
||||
<version>2.8.5</version>
|
||||
</dependency>
|
||||
<dependency><!-- für Unit-Tests -->
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>5.10.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency><!-- für Lombok -->
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency><!-- für net.jcip Annotationen -->
|
||||
<groupId>net.jcip</groupId>
|
||||
<artifactId>jcip-annotations</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<defaultGoal>clean compile exec:java</defaultGoal>
|
||||
<plugins>
|
||||
<plugin><!-- für Unit-Tests [mvn test] -->
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
</plugin>
|
||||
<plugin><!-- [mvn compile] -->
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.9.0</version>
|
||||
<configuration>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin><!-- [mvn exec:java] -->
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</plugin>
|
||||
<plugin><!-- [mvn javadoc:javadoc] -->
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.5.0</version>
|
||||
<configuration>
|
||||
<show>private</show>
|
||||
<locale>en_US</locale>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package pp;
|
||||
|
||||
import akka.actor.AbstractActor;
|
||||
import pp.messages.ResultMsg;
|
||||
|
||||
public class ListenerActor extends AbstractActor {
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder() //
|
||||
.match(ResultMsg.class, (msg) -> {
|
||||
msg.result().forEach(System.out::println);
|
||||
getContext().getSystem().terminate();
|
||||
}).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package pp;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.actor.Props;
|
||||
import pp.messages.FindMsg;
|
||||
|
||||
public class Main {
|
||||
|
||||
public static void main(String... args) {
|
||||
var system = ActorSystem.create();
|
||||
var master = system.actorOf(Props.create(MasterActor.class));
|
||||
String[] files = { "src/main/resources/test1.txt", "src/main/resources/test2.txt", "src/main/resources/test3.txt",
|
||||
"src/main/resources/test4.txt",
|
||||
"src/main/resources/test5.txt", "src/main/resources/test6.txt", "src/main/resources/test7.txt",
|
||||
"src/main/resources/test8.txt" };
|
||||
var msg = new FindMsg(Arrays.asList(files), "Erlang");
|
||||
master.tell(msg, ActorRef.noSender());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
package pp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.Props;
|
||||
import akka.routing.ActorRefRoutee;
|
||||
import akka.routing.RoundRobinRoutingLogic;
|
||||
import akka.routing.Routee;
|
||||
import akka.routing.Router;
|
||||
import pp.messages.FindMsg;
|
||||
import pp.messages.PleaseCleanupAndStop;
|
||||
import pp.messages.ResultMsg;
|
||||
import pp.messages.WorkMsg;
|
||||
|
||||
public class MasterActor extends AbstractActor {
|
||||
private int numOfChild;
|
||||
private final List<String> result = new ArrayList<>();
|
||||
private final ActorRef listener;
|
||||
|
||||
private final List<Routee> routees;
|
||||
private final Router router;
|
||||
|
||||
private static final int WORKER_NUM = 5;
|
||||
|
||||
public MasterActor() {
|
||||
this.listener = getContext().actorOf(Props.create(ListenerActor.class));
|
||||
this.routees = new ArrayList<>();
|
||||
for (var i = 0; i < MasterActor.WORKER_NUM; i++) {
|
||||
var r = getContext().actorOf(Props.create(WorkerActor.class));
|
||||
getContext().watch(r);
|
||||
this.routees.add(new ActorRefRoutee(r));
|
||||
}
|
||||
this.router = new Router(new RoundRobinRoutingLogic(), this.routees);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder() //
|
||||
.match(FindMsg.class, this::handleFindMsg) //
|
||||
.match(ResultMsg.class, this::handleResultMsg) //
|
||||
.build();
|
||||
}
|
||||
|
||||
private void handleFindMsg(FindMsg msg) {
|
||||
var filenames = msg.filenames();
|
||||
var searchword = msg.searchword();
|
||||
this.numOfChild = msg.filenames().size();
|
||||
for (var filename : filenames) {
|
||||
var job = new WorkMsg(filename, searchword);
|
||||
this.router.route(job, getSelf());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void handleResultMsg(ResultMsg msg) {
|
||||
this.numOfChild--;
|
||||
this.result.addAll(msg.result());
|
||||
if (this.numOfChild == 0) {
|
||||
for (var routee : this.routees) {
|
||||
routee.send(new PleaseCleanupAndStop(), getSelf());
|
||||
}
|
||||
this.listener.tell(new ResultMsg(this.result), getSelf());
|
||||
getContext().stop(getSelf());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package pp;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import akka.actor.AbstractActor;
|
||||
import pp.messages.PleaseCleanupAndStop;
|
||||
import pp.messages.ResultMsg;
|
||||
import pp.messages.WorkMsg;
|
||||
|
||||
public class WorkerActor extends AbstractActor {
|
||||
private Path path;
|
||||
private Pattern searchPattern;
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder() //
|
||||
.match(WorkMsg.class, this::handleWorkMsg) //
|
||||
.match(PleaseCleanupAndStop.class,
|
||||
(m) -> getContext().stop(getSelf())) //
|
||||
.build();
|
||||
}
|
||||
|
||||
private void handleWorkMsg(WorkMsg msg) throws IOException {
|
||||
this.path = Paths.get(msg.filename());
|
||||
this.searchPattern = Pattern
|
||||
.compile(".*\\b" + msg.searchword() + "\\b.*");
|
||||
var result = new ArrayList<String>();
|
||||
var lines = Files.readAllLines(this.path, StandardCharsets.UTF_8);
|
||||
var count = 0;
|
||||
for (var line : lines) {
|
||||
count++;
|
||||
if (this.searchPattern.matcher(line).matches()) {
|
||||
result.add(this.path + " " + count + " : " + line);
|
||||
}
|
||||
}
|
||||
getSender().tell(new ResultMsg(result), getSelf());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package pp.messages;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record FindMsg(List<String> filenames, String searchword) {
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
package pp.messages;
|
||||
|
||||
public record PleaseCleanupAndStop() {
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package pp.messages;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record ResultMsg(List<String> result) {
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
package pp.messages;
|
||||
|
||||
public record WorkMsg(String filename, String searchword) {
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Akka Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Erlang Idiom: Der Teil eines Programms der absolut korrekt sein muss, da er andere (potenziell unsicherere) Teile überwacht und ggf. neu startet.
|
||||
Man sollte bestrebt sein, den Error Kernel zu minimieren, damit wenigstens dort Fehlerfreiheit garantiert werden kann.
|
||||
Im Actor-Paradigma sollte jeder Prozess der einen Anwendungszweck hat (Worker) einen übergeordneten Supervisor-Prozess haben, der als dessen Error-Kernel fungiert.
|
||||
Es spricht nichts dagegen, auch komplexere Supervisor-Prozesse von einfacheren Error-Kernel-beinhaltenden Meta-Supervisor-Prozessen überwachen zu lassen.
|
||||
Loading…
Reference in New Issue