2010-02-22 2 views
11

Ich komme aus Java, wo ich Runnable s an eine ExecutorService übergeben würde, die von einem Thread-Pool unterstützt wird. Es ist sehr klar in Java, wie man die Größe des Thread-Pools begrenzt.Wie kann Nebenläufigkeit bei der Verwendung von Scala-Akteuren begrenzt werden?

Ich bin daran interessiert, Scala-Akteure zu verwenden, aber ich bin unklar, wie Sie die Nebenläufigkeit begrenzen können.

Sagen wir einfach, hypothetisch, dass ich einen Webdienst erstelle, der "Jobs" akzeptiert. Ein Job wird mit POST Anforderungen gesendet, und ich möchte, dass mein Dienst den Job in die Warteschlange einreiht und dann sofort 202 Accepted zurückgibt - d. H. Die Jobs werden asynchron verarbeitet.

Wenn ich Schauspieler verwende, um die Jobs in der Warteschlange zu verarbeiten, wie kann ich die Anzahl gleichzeitiger Jobs begrenzen, die verarbeitet werden?

Ich kann mir ein paar verschiedene Möglichkeiten vorstellen, dies zu erreichen; Ich frage mich, ob es eine Community Best Practice oder zumindest einige klar etablierte Ansätze gibt, die in der Scala-Welt etwas Standard sind.

Ein Ansatz, an den ich gedacht habe, ist ein einziger Koordinatorakteur, der die Jobwarteschlange und die jobverarbeitenden Akteure verwaltet; Ich nehme an, es könnte ein einfaches int-Feld verwenden, um zu verfolgen, wie viele Jobs gerade verarbeitet werden. Ich bin mir aber sicher, dass es bei diesem Ansatz einige Probleme geben würde, wie zum Beispiel, dass man nachverfolgen muss, wenn ein Fehler auftritt, um die Anzahl zu verringern. Deshalb frage ich mich, ob Scala bereits einen einfacheren oder besser eingekapselten Ansatz bietet.

BTW Ich habe versucht, diese Frage a while ago zu stellen, aber ich fragte es schlecht.

Danke!

Antwort

5

Sie können die Systemeigenschaften actors.maxPoolSize und actors.corePoolSize überschreiben, die die Größe des Actor-Thread-Pools begrenzen und dann so viele Jobs im Pool auslösen, wie Ihre Darsteller verarbeiten können. Warum denkst du, du brauchst Drossel deine Reaktionen?

+1

Sehr nützlich, danke! Ich bin mir nicht sicher, ob ich den Begriff _Throttle_ verwenden würde, aber es gibt Zeiten, in denen man die Anzahl der gleichzeitigen "Prozesse" beschränken muss, weil ihre Arbeit ressourcenintensiv ist. –

+3

Dieser Ansatz liefert möglicherweise nicht das gewünschte Ergebnis. Dadurch können Jobs in die Warteschlange gestellt werden, bis die JVM nicht mehr genügend Arbeitsspeicher hat. Wenn Sie die Anzahl der Threads beschränken, die von den Akteuren verwendet werden können, wird die Anzahl der Jobs, die gleichzeitig ausgeführt werden, begrenzt. Ich habe OOM-Fehler erzeugt, indem ich schneller als die Schauspieler Arbeit erzeugt habe, also muss man vorsichtig sein. –

+2

Ich denke, ein Nachteil dieses Ansatzes ist, dass es global ist. Manchmal habe ich verschiedene Arten von Prozessen, die ich ausführen muss, die unterschiedliche Ebenen der Ressourcennutzung haben - mit Java-Thread-Pools kann ich leicht verschiedene Pools mit unterschiedlichen Einstellungen verwenden. Mit 'actors.maxPoolSize' kann ich nur eine einzige Zahl für alle Darsteller verwenden, da sie alle aus demselben Thread-Pool stammen, oder? –

6

Ich würde Sie wirklich ermutigen, sich Akka anzusehen, eine alternative Actor-Implementierung für Scala.

http://www.akkasource.org

Akka hat bereits ein JAX-RS [1] Integration und man konnte, dass mit einem LoadBalancer im Konzert verwenden [2] zu drosseln, wie viele Aktionen können in parallell erfolgen:

[1 ] http://doc.akkasource.org/rest [2] http://github.com/jboner/akka/blob/master/akka-patterns/src/main/scala/Patterns.scala

+0

Interessant, ich werde es überprüfen, danke! –

3

Sie haben wirklich zwei Probleme hier.

Die erste ist, den Thread-Pool, der von den Schauspielern benutzt wird, unter Kontrolle zu halten. Dies kann durch Setzen der Systemeigenschaft actors.maxPoolSize erfolgen.

Die zweite ist ein rasantes Wachstum in der Anzahl der Aufgaben, die an den Pool übergeben wurden. Sie können sich mit diesem Problem befassen oder nicht, es ist jedoch durchaus möglich, Fehlerbedingungen wie Fehler wegen zu wenig Arbeitsspeichers und in einigen Fällen möglicherweise subtilere Probleme auszulösen, indem zu viele Aufgaben zu schnell generiert werden.

Jeder Worker-Thread behält eine Aufgabenwarteschlange bei. Die Dequeue wird als ein Array implementiert, das der Worker-Thread dynamisch auf eine maximale Größe vergrößert. In 2.7.x Die Warteschlange kann sich ziemlich groß entwickeln, und ich habe gesehen, dass in Kombination mit vielen gleichzeitigen Threads nicht genügend Speicherfehler auftreten. Die maximale Dequeue-Größe ist kleiner 2,8. Die Dequeue kann auch voll werden.

Um dieses Problem anzugehen, müssen Sie steuern, wie viele Aufgaben Sie generieren, was wahrscheinlich eine Art Koordinator bedeutet, wie Sie es beschrieben haben. Ich habe dieses Problem festgestellt, wenn die Akteure, die eine Art von Datenverarbeitungspipeline initiieren, viel schneller sind als diejenigen, die später in der Pipeline sind. Um den Prozess zu steuern, habe ich normalerweise die Schauspieler später in der Kette, um Schauspieler früher in der Kette alle X-Nachrichten zurück zu pingen, und die früher in der Kette nach X-Nachrichten zu stoppen und auf den Ping zurück zu warten. Sie könnten es auch mit einem zentralisierteren Koordinator machen.