2012-03-30 15 views
6

Czy równoległe kolekcje przeznaczone są do wykonywania operacji z efektami ubocznymi? Jeśli tak, jak można uniknąć warunków wyścigu? Na przykład:jak uniknąć wyścigów z równoległymi kolekcjami scala

var sum=0 
(1 to 10000).foreach(n=>sum+=n); println(sum) 

50005000 

Nie ma problemu z tym. Ale jeśli spróbować parallelize warunki wyścigowe zdarzyć:

var sum=0 
(1 to 10000).par.foreach(n=>sum+=n);println(sum) 

49980037 
+0

Nie, efekty uboczne są złe. Jeśli nie masz stanu, znacznie trudniej jest mieć warunki wyścigowe. – PlexQ

Odpowiedz

17

Szybka odpowiedź: nie rób tego. Kod równoległy powinien być równy równoległy, a nie współbieżny.

Lepsza odpowiedź:

val sum = (1 to 10000).par.reduce(_+_) // depends on commutativity and associativity 

Zobacz także aggregate.

4

równoległa sprawa nie działa, ponieważ nie używać zmiennych lotnych stąd nie zapewniające widoczność pisze i dlatego masz wiele wątków, które wykonaj następujące czynności:

  1. czytać sum do rejestru
  2. dodać do rejestru o wartości
  3. sum zapisze zaktualizowaną wartość z powrotem do pamięci

If 2 wątki zrobić pierwszy krok 1 o ne po drugiej, a następnie wykonaj pozostałe kroki powyżej w dowolnej kolejności, w końcu nadpisują jedną z aktualizacji.

  1. Użyj adnotacji @volatile, aby zapewnić widoczność sum podczas robienia czegoś takiego. Zobacz here.
  2. Nawet z @volatile, ze względu na brak atomowości przyrostu, będziesz tracić kilka przyrostów. Powinieneś użyć AtomicInteger s i ich incrementAndGet.
  3. Chociaż użycie liczników atomowych zapewni poprawność, posiadanie wspólnych zmiennych znacznie utrudnia wydajność - twoja współdzielona zmienna jest teraz wąskim gardłem wydajności, ponieważ każdy wątek będzie próbował atomowo zapisywać do tej samej linii pamięci podręcznej. Jeśli pisałeś do tej zmiennej nieczęsto, nie byłoby to problemem, ale ponieważ robisz to w każdej iteracji, tutaj nie będzie przyspieszenia - w rzeczywistości, z powodu przeniesienia własności cache-line pomiędzy procesorami, prawdopodobnie będzie wolniej .

Tak więc, jak zasugerował Daniel - użyj do tego celu reduce.

Powiązane problemy