2012-03-30 14 views
6

Le raccolte parallele sono progettate per eseguire operazioni con effetti collaterali? Se sì, come puoi evitare le condizioni di gara? Per esempio:come evitare le condizioni di gara con le collezioni scala parallela

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

50005000 

alcun problema con questo. Ma se provate a parallelizzare, condizioni di gara accada:

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

49980037 
+0

No, gli effetti collaterali sono negativi. Se non hai lo stato, è molto più difficile avere condizioni di gara. – PlexQ

risposta

17

risposta rapida: non farlo. Il codice parallelo deve essere parallelo, non simultaneo.

Meglio risposta:

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

Vedi anche aggregate.

4

caso parallela non funziona perché non si utilizza le variabili volatili, quindi, non assicurando visibilità dei tuoi scrive e perché avete più thread che effettuare le seguenti operazioni:

  1. leggere sum in un registro
  2. aggiungere al registro con il valore sum
  3. scrivere il valore aggiornato alla memoria

se 2 filettature eseguire il passaggio 1 prima o uno dopo l'altro e quindi procedere al resto dei passaggi sopra riportati in qualsiasi ordine, finiranno per sovrascrivere uno degli aggiornamenti.

  1. Usa @volatile annotazione per garantire la visibilità delle sum quando si fa qualcosa di simile. Vedi here.
  2. Anche con @volatile, a causa della non atomicità dell'incremento si perderanno alcuni incrementi. È necessario utilizzare AtomicInteger s e il loro incrementAndGet.
  3. Sebbene l'utilizzo di contatori atomici garantisca la correttezza, la presenza di variabili condivise qui ostacola notevolmente le prestazioni: la variabile condivisa ora è un collo di bottiglia delle prestazioni poiché ogni thread proverà a scrivere in modo atomico sulla stessa riga della cache. Se hai scritto questa variabile raramente, non sarebbe un problema, ma dal momento che lo fai in ogni iterazione, non ci sarà alcuna accelerazione qui - infatti, a causa del trasferimento della proprietà della cache-line tra i processori, sarà probabilmente più lento .

Quindi, come suggerito da Daniel, utilizzare reduce per questo.

Problemi correlati