2010-11-29 4 views
5

Ich bin neu bei Scala im Allgemeinen und bei Schauspielern im Besonderen und mein Problem ist so grundlegend, dass die Online-Ressourcen, die ich gefunden habe, es nicht abdecken.Verwenden von Actors zum Ausnutzen von Kernen

Ich habe einen CPU-intensive, leicht parallelisieren Algorithmus, der auf eine n -Core Maschine ausgeführt werden (ich weiß nicht, n). Wie implementiere ich das in Actors, damit alle verfügbaren Cores das Problem lösen?

Der erste Weg, dachte ich an das Problem in m Stücke auf einfache Pause war (wo m einige mittlere Anzahl wie 10.000) und m Schauspieler, eine für jedes Stück, geben Sie jeder Schauspieler seine kleinen Stück und lass sie gehen.

Irgendwie fiel mir das als ineffizient auf. Zillionen von Schauspielern, die einfach nur rumhängen, auf CPU-Liebe warten, sinnlos den Kontext wechseln ...

Dann dachte ich mir, mach eine kleinere Anzahl von Actors und füttere jedes einzelne Stück. Das Problem war, dass es keinen Grund gibt, zu erwarten, dass die Teile die gleiche Größe haben, so dass ein Kern stecken bleiben kann, wobei viele seiner Aufgaben immer noch in der Warteschlange stehen, während andere Kerne inaktiv sind.

Ich drehte mich mit einem Supervisor herum, der wusste, welche Schauspieler beschäftigt waren, und erkannte schließlich, dass dies ein gelöstes Problem sein musste. Es muss ein Standardmuster (vielleicht sogar eine Standardbibliothek) geben, um mit diesem sehr allgemeinen Problem umzugehen. Irgendwelche Vorschläge?

Antwort

8

Werfen Sie einen Blick auf die Bibliothek Akka, die eine Implementierung von Aktoren enthält. Die Dispatchers Module bietet Ihnen mehr Optionen zum Beschränken von Akteuren auf CPU-Threads (HawtDispatch-basierte ereignisgesteuerte) und/oder das Ausgleichen der Arbeitslast (Work-Stealing ereignisbasiert).

3

Sie sollten in Futures nachdenken, denke ich. In der Tat benötigen Sie wahrscheinlich einen Threadpool, der einfach Threads in die Warteschlange stellt, wenn eine maximale Anzahl von Threads erreicht wurde.

Hier ist ein kleines Beispiel mittels Futures: http://blog.tackley.net/2010/01/scala-futures.html

ich auch, dass Sie wirklich, da Sie nicht zu viel Aufmerksamkeit Umschalten in den Kontext zahlen würde vorschlagen, nicht alles tun kann, sondern verlassen sich auf die zugrunde liegende Implementierung. Natürlich wäre es eine Faustregel, die aktiven Threads um die Anzahl physischer Kerne herum zu halten, aber wie ich oben angemerkt habe, könnte dies durch einen Threadpool mit einer Fifo-Warteschlange gehandhabt werden.

HINWEIS, dass ich nicht weiß, ob Akteure im Allgemeinen oder Futures mit dieser Art von Pool implementiert sind.

Für Thread-Pools, sieh dir das an: http://www.scala-lang.org/api/current/scala/concurrent/ThreadPoolRunner.html

und vielleicht dies: http://www.scala-lang.org/api/current/scala/actors/scheduler/ResizableThreadPoolScheduler.html

Viel Glück

EDIT

Schauen Sie sich dieses Stück Code unter Verwendung von Futures:

import scala.actors.Futures._ 

object FibFut { 
    def fib(i: Int): Int = if (i < 2) 1 else fib(i - 1) + fib(i - 2) 
    def main(args: Array[String]) { 
    val fibs = for (i <- 0 to 42) yield future { fib(i) } 
    for (future <- fibs) println(future()) 
    } 
} 

Es zeigt einen sehr guten Punkt über Futures, nämlich dass Sie entscheiden, in welcher Reihenfolge die Ergebnisse erhalten (im Gegensatz zu den normalen Mailbox-System, das ein Fifo-System verwendet, d.h. der schnellste Akteur sendet sein Ergebnis zuerst).

0

Für jedes bedeutende Projekt habe ich in der Regel einen Supervisor-Akteur, eine Sammlung von Arbeiterakteuren, von denen jeder jede notwendige Arbeit leisten kann, und eine große Anzahl von Arbeiten. Obwohl ich das ziemlich oft mache, habe ich es nie in eine (persönliche) Bibliothek gestellt, weil die Operationen jedes Mal so unterschiedlich sind und der Overhead im Vergleich zum gesamten Coding-Projekt ziemlich klein ist.

3

Im Allgemeinen gibt es 2 Arten von Akteuren: diejenigen, die an Threads (ein Thread pro Akteur) gebunden sind, und solche, die 1+ Thread teilen, arbeiten hinter einem Scheduler/Dispatcher, der Ressourcen verteilt (= Möglichkeit, eine Aufgabe/handle eingehende Nachricht gegen kontrollierten Thread-Pool oder einen einzelnen Thread).

Ich nehme an, Sie verwenden zweite Art von Akteuren - ereignisgesteuerte Akteure, weil Sie erwähnen, dass Sie 10k von ihnen ausführen. Egal wie viele ereignisgesteuerte Schauspieler Sie haben (Tausende oder Millionen), alle werden für den kleinen Threadpool kämpfen, um die Nachricht zu bearbeiten. Daher haben Sie sogar eine schlechtere Leistung, Ihre Aufgabenwarteschlange in diese große Anzahl von Teilen zu teilen - der Scheduler wird entweder versuchen, Nachrichten an 10k Akteure gegen einen festen Thread-Pool zu behandeln (was langsam ist) oder wird neue Threads im Pool zuweisen (wenn der Pool nicht begrenzt ist), was gefährlich ist (im schlimmsten Fall werden 10k Threads gestartet, um Nachrichten zu verarbeiten).

Ereignisgesteuerte Aktoren eignen sich für kurzzeitige (idealerweise nicht blockierende) Aufgaben. Wenn Sie mit CPU-intensiven Aufgaben zu tun haben, würde ich die Anzahl der Threads im Scheduler/Dispatcher-Pool (wenn Sie ereignisgesteuerte Akteure verwenden) oder Akteure selbst (wenn Sie threadbasierte Akteure verwenden) auf die Anzahl der Kerne beschränken die beste Leistung erzielen.

Wenn Sie diese automatisch durchgeführt werden soll (anpassen Anzahl der Threads in Dispatcher-Pool auf die Anzahl der Kerne), sollten Sie verwenden HawtDisaptch (oder es ist Akka implementation), wie es früher vorgeschlagen wurde:

Der 'HawtDispatcher' verwendet die HawtDispatch Threading-Bibliothek, die ist ein Java-Klon von libdispatch. Alle Aktoren mit dieser Art von Dispatcher werden in einem einzigen systemweiten Threadpool mit fester Größe ausgeführt. Die Anzahl der Threads stimmt mit der Anzahl der Cores überein, die auf Ihrem System verfügbar sind. Die Dispatcher liefert Nachrichten an die Akteure in der Reihenfolge, dass sie Produzent am Absender waren.

0

Be aware of actor starvation Wenn Sie den allgemeinen Aktor threapool verwenden. Am Ende habe ich meinen eigenen threadeigenen Threadpool verwendet, um die Parallelisierung einer lang andauernden, gleichzeitigen Aufgabe zu bewältigen.

0

Die kommende Scala 2.9 wird voraussichtlich parallele Datenstrukturen enthalten, die dies für einige Anwendungen automatisch behandeln sollten. Auch wenn es keine Actors verwendet, kann es etwas für Ihr Problem sein.

Während diese Funktion ursprünglich für 2,8 geplant war, wurde sie auf die nächste Hauptversion verschoben.

Eine Präsentation der letzten ScalaDays ist hier:

http://days2010.scala-lang.org/node/138/140