Szukaj…


Uwagi

Kolekcje równoległe ułatwiają programowanie równoległe, ukrywając szczegóły paralelizacji niskiego poziomu. Ułatwia to korzystanie z architektur wielordzeniowych. Przykłady równoległych kolekcji obejmują ParArray , ParVector , mutable.ParHashMap , immutable.ParHashMap i ParRange . Pełna lista znajduje się w dokumentacji .

Tworzenie i używanie równoległych kolekcji

Aby utworzyć kolekcję równoległą z kolekcji sekwencyjnej, wywołaj metodę par . Aby utworzyć kolekcję sekwencyjną z kolekcji równoległej, wywołaj metodę seq . Ten przykład pokazuje, w jaki sposób zamieniasz zwykły Vector w ParVector , a następnie ponownie:

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)

Metodę par można połączyć w łańcuch, umożliwiając konwersję kolekcji sekwencyjnej na kolekcję równoległą i natychmiastowe wykonanie na niej akcji:

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)

W tych przykładach praca jest faktycznie podzielona na wiele jednostek przetwarzania, a następnie ponownie dołączona po zakończeniu pracy - bez konieczności interwencji programisty.

Pułapki

Nie należy używać kolekcji równoległych, gdy elementy kolekcji muszą być odbierane w określonej kolejności.

Kolekcje równoległe wykonują operacje jednocześnie. Oznacza to, że cała praca jest podzielona na części i rozdzielona między różne procesory. Każdy procesor nie jest świadomy pracy wykonywanej przez innych. Jeśli kolejność kolekcji ma znaczenie, praca przetwarzana równolegle nie jest deterministyczna. (Dwukrotne uruchomienie tego samego kodu może dać różne wyniki).


Operacje niezwiązane z asocjacją

Jeśli operacja nie ma asocjacji (jeśli kolejność wykonywania ma znaczenie), wynik w równoległej kolekcji będzie niedeterministyczny.

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

Skutki uboczne

Operacje, które mają skutki uboczne, takie jak foreach , mogą nie być wykonywane zgodnie z potrzebami w równoległych kolekcjach z powodu warunków wyścigu. Unikaj tego, używając funkcji, które nie mają skutków ubocznych, takich jak reduce lub 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
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow