2010-09-18 11 views
10

Quali sono gli analoghi di QtConcurrent per Scala (o Java)? Cioè implementazione semplificata di MapReduce, la mappa parallela e foldl. GrazieAnaloghi Scala di QtConcurrent

+0

vedere anche http://stackoverflow.com/questions/1751953/concurrent-map-foreach-in-scala/1753224#1753224 – oluies

risposta

3

È possibile percorrere una lunga strada utilizzando semplicemente scala.actors.Futures e normale map/flatMap per le raccolte. No facilmente parallelizzabile fold, tuttavia.

Se si utilizzano host multipli, utilizzare Akka's send-and-receive-future.

12

È possibile utilizzare le Collezioni parallele Scala. Attualmente fanno parte delle uscite serali di Scala e verranno rilasciati in Scala 2.9. L'idea è che la maggior parte delle operazioni disponibili nelle collezioni regolari siano parallelizzate, in modo che le raccolte parallele possano essere utilizzate allo stesso modo.

Attualmente sono disponibili alcuni tipi di raccolta: intervalli paralleli, array paralleli e tentativi di hash paralleli. Per esempio, è possibile richiamare un parallelo map e fold operazioni su un array parallelo come questo:

scala> val pa = (0 until 10000).toArray.par 
pa: scala.collection.parallel.mutable.ParArray[Int] = ParArray(0, 1, 2, 3, 4, 5, 6,... 

scala> pa.map(_ + 1) 
res0: scala.collection.parallel.mutable.ParArray[Int] = ParArray(1, 2, 3, 4, 5, 6, 7,... 

scala> pa map { v => if (v % 2 == 0) v else -v } 
res1: scala.collection.parallel.mutable.ParArray[Int] = ParArray(0, -1, 2, -3, 4, -5,... 

scala> pa.fold(0) { _ + _ } 
res2: Int = 49995000 

Non ci sono altre operazioni di raccolta parallela disponibili pure. Nota che fold deve assumere un operatore associativo - nell'esempio sopra, l'addizione è associativa ((A + B) + C == A + (B + C)), cioè puoi aggiungere sottosequenze di numeri in qualsiasi ordine e sarai sempre ottenere la stessa somma (reduce ha un contratto simile).

Un'altra cosa da tenere presente è che le chiusure passate alle raccolte parallele vengono richiamate simultaneamente. Se hanno effetti collaterali, come la modifica di una variabile locale nell'ambiente, questi accessi devono essere sincronizzati. Per esempio, si potrebbe fare qualcosa di simile:

scala> var a = 0                                         
a: Int = 0                                          

scala> pa foreach { a += _ }                                      

scala> a                                           
res1: Int = 49995000    

scala> a = 0 
a: Int = 0 

scala> pa foreach { a += _ } 

scala> a 
res7: Int = 49990086 

ed avere risultati diversi ogni volta, perché il foreach invoca { a += _ } in parallelo. Nell'esempio sopra, a dovrebbe essere sincronizzato, protetto con un blocco o atomico.

Ma l'idea è di utilizzare i combinatori integrati per eseguire un'attività e orientarsi verso la programmazione funzionale, evitando gli effetti collaterali locali come nell'esempio sopra.

Si consiglia di leggere un po 'di più sui meccanismi interni nei collegamenti forniti nell'altra risposta.

+0

Risposta molto buona con una "spinta" lontano dalle mutazioni ;-) –