Als in meiner eigenen Antwort auf meine eigene Frage , ich habe die Situation, dass ich eine große Anzahl von Ereignissen bearbeite, die in einer Warteschlange ankommen. Jedes Ereignis wird auf genau dieselbe Weise behandelt und jedes kann sogar unabhängig von allen anderen Ereignissen gehandhabt werden.
Mein Programm nutzt das Scala Concurrency Framework und viele der involvierten Prozesse werden als Actor
s modelliert. Da Actor
s ihre Nachrichten sequentiell verarbeiten, sind sie für dieses spezielle Problem nicht gut geeignet (auch wenn meine anderen Akteure Aktionen ausführen, die sequentiell sind ). Da ich möchte, dass Scala alle Thread-Erstellung "kontrolliert" (was ich davon ausgehe, dass es einen Nebenläufersystem hat), scheint es, als hätte ich zwei Möglichkeiten:
Actor
, um sie gleichzeitig mit einem anderen Mechanismus zu verarbeiten Ich hätte gedacht, dass Nr. 1 die Verwendung des Akteurs-Subsystems negiert: Wie viele Prozessor-Akteure soll ich erstellen? ist eine offensichtliche Frage. Diese Dinge werden angeblich vor mir verborgen und durch das Subsystem gelöst.
Meine Antwort lautete:
%Vor%Gibt es einen besseren Ansatz? Ist das falsch?
edit: Ein möglicherweise besserer Ansatz ist:
%Vor%Das scheint wie ein Duplikat einer anderen Frage zu sein. Also werde ich meine Antwort duplizieren
Schauspieler verarbeiten jeweils eine Nachricht. Das klassische Muster, um mehrere Nachrichten zu verarbeiten, besteht darin, eine Koordinator-Akteur-Front für einen Pool von Konsumenten-Akteuren zu haben. Wenn Sie react verwenden, kann der Consumer-Pool zwar groß sein, wird jedoch nur eine kleine Anzahl von JVM-Threads verwenden. Hier ist ein Beispiel, in dem ich einen Pool von 10 Konsumenten und einen Koordinator für sie kreiere.
%Vor%Dieser Code testet, um festzustellen, welcher Verbraucher verfügbar ist, und sendet eine Anfrage an diesen Verbraucher. Alternativen sind nur zufällig den Verbrauchern zuzuweisen oder einen Round-Robin-Scheduler zu verwenden.
Je nachdem, was Sie tun, könnten Sie besser mit Scala's Futures bedient werden. Wenn Sie zum Beispiel keine Schauspieler brauchen, könnten alle oben genannten Maschinen als
geschrieben werden %Vor% Wenn die Ereignisse unabhängig voneinander behandelt werden können, warum stehen sie in einer Warteschlange? Wenn Sie nichts anderes über Ihr Design wissen, scheint dies ein unnötiger Schritt zu sein. Wenn Sie die Funktion process
zusammen mit dem erstellen könnten, was diese Ereignisse auslöst, könnten Sie möglicherweise die Warteschlange umgehen.
Ein Akteur ist im Wesentlichen ein gleichzeitiger Effekt, der mit einer Warteschlange ausgestattet ist. Wenn Sie mehrere Nachrichten gleichzeitig verarbeiten möchten, möchten Sie nicht wirklich einen Akteur. Sie möchten nur, dass eine Funktion (Any = & gt; ()) zur Ausführung zu einem passenden Zeitpunkt geplant wird.
Nachdem Sie das gesagt haben, ist Ihr Ansatz sinnvoll , wenn Sie innerhalb der Actors-Bibliothek bleiben möchten und die Ereigniswarteschlange nicht unter Ihrer Kontrolle steht.
Scalaz unterscheidet zwischen Akteuren und gleichzeitigen Effekten. Während Actor
sehr leicht ist, ist scalaz.concurrent.Effect
immer noch leichter. Hier ist Ihr Code grob in die Scalaz-Bibliothek übersetzt:
Dies ist mit dem neuesten Stammkopf, noch nicht veröffentlicht.
Der Zweck eines Akteurs (nun, einer davon) besteht darin, sicherzustellen, dass der Status innerhalb des Akteurs immer nur von einem einzigen Thread gleichzeitig erreicht werden kann. Wenn die Verarbeitung einer Nachricht nicht von einem veränderlichen Status innerhalb des Akteurs abhängt, wäre es wahrscheinlich zweckmäßiger, eine Aufgabe einfach an einen Scheduler oder einen Thread-Pool zur Verarbeitung zu übergeben. Die zusätzliche Abstraktion, die der Schauspieler bietet, kommt dir tatsächlich im Weg.
Es gibt bequeme Methoden in scala.actors.Scheduler dafür, oder Sie könnten einen Executor von java.util.concurrent verwenden.
Actors sind viel leichter als Threads, und als eine andere Option können Sie Actor-Objekte wie Runnable-Objekte verwenden, die Sie zum Senden an einen Thread-Pool verwenden. Der Hauptunterschied besteht darin, dass Sie sich nicht um den Thread-Pool kümmern müssen - der Thread-Pool wird vom Actor-Framework für Sie verwaltet und ist hauptsächlich ein Konfigurationsaspekt.
%Vor%Um eine Nachricht zu senden, sagen Sie Folgendes:
%Vor%, was
entspricht %Vor%von Ihrer Frage.
Dieses Muster wurde erfolgreich mit 1 Million Nachrichten getestet, die in etwa 10 Sekunden auf einem Quad-Core-i7-Laptop gesendet und empfangen wurden.
Hoffe, das hilft.
Tags und Links scala concurrency actor