Supponiamo di voler utilizzare una mappa mutabile in Scala per tenere traccia del numero di volte in cui ho visto alcune stringhe. In un contesto thread singolo, questo è facile:Thread: trasformazione sicura di un valore in una mappa mutabile
import scala.collection.mutable.{ Map => MMap }
class Counter {
val counts = MMap.empty[String, Int].withDefaultValue(0)
def add(s: String): Unit = counts(s) += 1
}
Purtroppo questo non è thread-safe, poiché la get
e update
non accada atomicamente.
Concurrent maps aggiungere a few atomic operations alla mappa API mutevole, ma non quello che ho bisogno, che sarebbe simile a questa:
def replace(k: A, f: B => B): Option[B]
So che posso usare ScalaSTM s' TMap
:
import scala.concurrent.stm._
class Counter {
val counts = TMap.empty[String, Int]
def add(s: String): Unit = atomic { implicit txn =>
counts(s) = counts.get(s).getOrElse(0) + 1
}
}
Ma (per ora) è ancora una dipendenza extra. Altre opzioni includono gli attori (un'altra dipendenza), la sincronizzazione (potenzialmente meno efficiente) o Java atomic references (less idiomatic).
In generale eviterei mappe mutabili a Scala, ma a volte ho bisogno di questo genere di cose, e più recentemente ho usato l'approccio STM (invece di incrociare le dita e sperare che non capisco morso dalla soluzione ingenua).
So che ci sono un certo numero di compromessi qui (dipendenze extra vs. prestazioni rispetto alla chiarezza, ecc.), Ma c'è qualcosa come una risposta "giusta" a questo problema in Scala 2.10?
che dire di un singolo attore Akka che scrive alla mappa mutevole? "Counter.add" invia semplicemente un messaggio ignifugo. Per quanto riguarda le letture, a seconda delle esigenze possono accadere contemporaneamente o passare attraverso l'attore. – gourlaysama