2010-04-02 3 views
8

Ich bin sicher, dass dies eine sehr einfache Frage, aber peinlich ich meinen Kopf nicht drum herum kommen zu sagen:Einfache Scala Schauspieler Frage

Ich habe eine Liste von Werten in Scala. Ich möchte verwenden Sie Akteure, um einige (externe) Anrufe mit jedem Wert, parallel zu machen.

Ich möchte warten, bis alle Werte verarbeitet wurden, und dann fortfahren.

Es gibt keine gemeinsamen Werte, die geändert werden.

Könnte jemand beraten?

Dank

Antwort

17

Es ist eine Schauspieler betriebene Klasse in Scala, die genau gemacht hat für diese Art von Problem: Futures. Dieses Problem würde so gelöst werden:

// This assigns futures that will execute in parallel 
// In the example, the computation is performed by the "process" function 
val tasks = list map (value => scala.actors.Futures.future { process(value) }) 

// The result of a future may be extracted with the apply() method, which 
// will block if the result is not ready. 
// Since we do want to block until all results are ready, we can call apply() 
// directly instead of using a method such as Futures.awaitAll() 
val results = tasks map (future => future.apply()) 

Dort gehen Sie. Nur das.

+1

Das ist zu einfach, da muss etwas nicht stimmen ;-) Sieht gut aus, nochmals vielen Dank. – 7zark7

+0

@ 7zark7 Ja, ich habe mich auch so gefühlt. :-) Es kompiliert aber, und ich glaube nicht, dass ich einen bestimmten Fehler gemacht habe. Stellen Sie sicher, dass "process" keine Exceptions auslöst, und beachten Sie, dass es bei I/O möglicherweise nicht so gut funktioniert, wie Sie es erwarten, da die laufenden Futures nur die wartenden Threads blockieren. –

+1

Es funktioniert. Tatsächlich habe ich es getestet, um sicherzustellen, dass es ebenso effizient funktioniert wie der Schauspieler-Stil (ich war neugierig, da ich das vorher nicht getan hatte oder in den 'Futures'-Quellcode geschaut habe), und das tut es auch. –

9

Arbeiter erstellen und sie bitten, für Futures !! verwendet wird; dann lese die Ergebnisse ab (die berechnet werden und parallel eingehen, sobald sie fertig sind; du kannst sie dann verwenden). Zum Beispiel:

object Example { 
    import scala.actors._ 
    class Worker extends Actor { 
    def act() { Actor.loop { react { 
     case s: String => reply(s.length) 
     case _ => exit() 
    }}} 
    } 
    def main(args: Array[String]) { 
    val arguments = args.toList 
    val workers = arguments.map(_ => (new Worker).start) 
    val futures = for ((w,a) <- workers zip arguments) yield w !! a 
    val results = futures.map(f => f() match { 
     case i: Int => i 
     case _ => throw new Exception("Whoops--didn't expect to get that!") 
    }) 
    println(results) 
    workers.foreach(_ ! None) 
    } 
} 

Dies hat eine sehr kostengünstige Berechnung - die Länge eines Strings Berechnung - aber man kann etwas teuer dort setzen, um sicherzustellen, dass es wirklich parallel geschieht (das Letzte, was Falle der Akt Block sollte sein, mit der Antwort zu antworten). Beachten Sie, dass wir auch einen Fall für den Arbeiter einschließen, um sich selbst zu schließen, und wenn wir fertig sind, sagen wir den Arbeitern, dass sie herunterfahren sollen. (In diesem Fall wird jeder nicht-String schließt die Arbeiter nach unten.)

Und wir können dies sicher zu machen versuchen, es funktioniert:

scala> Example.main(Array("This","is","a","test")) 
List(4, 2, 1, 4) 
+0

Vielen Dank - Ich schien die Erwähnung von Futures und Nutzung von !! vor dem. – 7zark7

+0

Ich sollte darauf hinweisen, dass ich vielleicht zu buchstäblich mit der Verwendung von Schauspielern war: Wenn Sie sie nicht wiederverwenden, ist Daniels Antwort noch kürzer und direkter, um zu der von Ihnen gewünschten parallelen Berechnung zu gelangen. (Z. B. Futures ohne Akteure verwenden.) –

+0

@Mog - 'f()' erhält das Ergebnis der Berechnung (Blöcke, bis es verfügbar ist). Die "Übereinstimmung" liegt darin, dass die von Schauspielern gesendeten Nachrichten als "Any" getippt werden - wir erwarten, dass wir einen Int zurückbekommen (also suchen wir danach), aber wenn wir aus irgendeinem unerwarteten Grund etwas anderes bekommen, werfen wir eine Ausnahme aus . –