Ricerca…


Osservazioni

Le raccolte parallele facilitano la programmazione parallela nascondendo i dettagli di parallelizzazione di basso livello. Ciò facilita l'utilizzo di architetture multi-core. Esempi di collezioni parallele includono ParArray , ParVector , mutable.ParHashMap , immutable.ParHashMap e ParRange . Un elenco completo può essere trovato nella documentazione .

Creazione e utilizzo di raccolte parallele

Per creare una raccolta parallela da una collezione sequenziale, chiama il metodo par . Per creare una collezione sequenziale da una raccolta parallela, chiamare il metodo seq . Questo esempio mostra come si trasforma un Vector normale in un ParVector e poi di nuovo:

scala> val vect = (1 to 5).toVector
vect: Vector[Int] = Vector(1, 2, 3, 4, 5)

scala> val parVect = vect.par
parVect: scala.collection.parallel.immutable.ParVector[Int] = ParVector(1, 2, 3, 4, 5)

scala> parVect.seq
res0: scala.collection.immutable.Vector[Int] = Vector(1, 2, 3, 4, 5)

Il metodo par può essere concatenato, consentendo di convertire una collezione sequenziale in una raccolta parallela e eseguire immediatamente un'azione su di essa:

scala> vect.map(_ * 2)
res1: scala.collection.immutable.Vector[Int] = Vector(2, 4, 6, 8, 10)

scala> vect.par.map(_ * 2)
res2: scala.collection.parallel.immutable.ParVector[Int] = ParVector(2, 4, 6, 8, 10)

In questi esempi, il lavoro viene effettivamente suddiviso in più unità di elaborazione e quindi ricongiunto dopo il completamento del lavoro, senza richiedere l'intervento dello sviluppatore.

insidie

Non utilizzare raccolte parallele quando gli elementi della raccolta devono essere ricevuti in un ordine specifico.

Le raccolte parallele eseguono operazioni contemporaneamente. Ciò significa che tutto il lavoro è diviso in parti e distribuito a diversi processori. Ogni processore non è consapevole del lavoro svolto da altri. Se l' ordine della raccolta è importante, il lavoro elaborato in parallelo non è deterministico. (L'esecuzione dello stesso codice due volte può produrre risultati diversi).


Operazioni non associative

Se un'operazione è non associativa (se l'ordine di esecuzione è importante), il risultato su una raccolta parallela sarà non deterministico.

scala> val list = (1 to 1000).toList
list: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10...

scala> list.reduce(_ - _)
res0: Int = -500498

scala> list.reduce(_ - _)
res1: Int = -500498

scala> list.reduce(_ - _)
res2: Int = -500498

scala> val listPar = list.par
listPar: scala.collection.parallel.immutable.ParSeq[Int] = ParVector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10...

scala> listPar.reduce(_ - _)
res3: Int = -408314

scala> listPar.reduce(_ - _)
res4: Int = -422884

scala> listPar.reduce(_ - _)
res5: Int = -301748

Effetti collaterali

Le operazioni che hanno effetti collaterali, come foreach , potrebbero non essere eseguite come desiderato su raccolte parallele a causa delle condizioni di gara. Evita questo utilizzando funzioni che non hanno effetti collaterali, come reduce o map .

scala> val wittyOneLiner = Array("Artificial", "Intelligence", "is", "no", "match", "for", "natural", "stupidity")

scala> wittyOneLiner.foreach(word => print(word + " "))
Artificial Intelligence is no match for natural stupidity 

scala> wittyOneLiner.par.foreach(word => print(word + " "))
match natural is for Artificial no stupidity Intelligence

scala> print(wittyOneLiner.par.reduce{_ + " " + _})
Artificial Intelligence is no match for natural stupidity

scala> val list = (1 to 100).toList
list: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15...


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow