Подтвердить что ты не робот

Рекомендации по перемещению в Scala concurrent.Map

ScalaDoc говорит об этом как о concurrentMap: "Устаревший (начиная с версии 2.10.0) вместо этого используйте scala.collection.concurrent.Map". К сожалению, остальные Scala docs не были обновлены и все еще ссылаются на concurrentMap.

Я попытался смешать в concurrent.Map в HashMap со следующими результатами:

scala> val mmap = new mutable.HashMap[String, String] with collection.concurrent.Map[String, String]
<console>:16: error: object creation impossible, since:
it has 4 unimplemented members.
/** As seen from anonymous class $anon, the missing signatures are as follows.
 *  For convenience, these are usable as stub implementations.
 */
  def putIfAbsent(k: String,v: String): Option[String] = ???
  def remove(k: String,v: String): Boolean = ???
  def replace(k: String,v: String): Option[String] = ???
  def replace(k: String,oldvalue: String,newvalue: String): Boolean = ???

       val mmap = new mutable.HashMap[String, String] with collection.concurrent.Map[String, String]

Итак, мы видим, что вместо простого mixin необходимо также реализовать некоторые методы. Это лучший способ использовать concurrent.Map, или есть лучший способ?

4b9b3361

Ответ 1

Признак scala.collection.concurrent.Map не должен смешиваться с существующим изменяемым Scala Map, чтобы получить потокобезопасную версию экземпляра карты. Для этой цели существовал SynchronizedMap mixin до 2.11, но теперь устарел.

В настоящее время Scala имеет реализацию scala.collection.concurrent.TrieMap для интерфейса scala.collection.concurrent.Map, но также может переносить классы Java.

scala.collection.concurrent.Map, в версиях до 2.10, известных как scala.collection.mutable.ConcurrentMap, интерфейс используется, когда вы:

  • хотите реализовать свой собственный параллельный, потокобезопасный Map с нуля

  • хотите обернуть существующую реализацию параллельной карты Java:

например:

import scala.collection._
import scala.collection.convert.decorateAsScala._
import java.util.concurrent.ConcurrentHashMap

val map: concurrent.Map[String, String] = new ConcurrentHashMap().asScala
  • хотите написать общий код, который работает с параллельными картами, и не хотят фиксировать конкретную реализацию:

например:.

import scala.collection._

def foo(map: concurrent.Map[String, String]) = map.putIfAbsent("", "")

foo(new concurrent.TrieMap)
foo(new java.util.concurrent.ConcurrentSkipListMap().asScala)
  • вы могли бы реализовать свою собственную оболочку вокруг однопоточной изменчивой реализации карты с помощью синхронизации (но вам нужно было бы убедиться, что ваша программа обращается к изменяемой карте только через эту оболочку и никогда напрямую).

например:.

class MySynchronizedMap[K, V](private val underlying: mutable.Map[K, V])
extends concurrent.Map[K, V] {
  private val monitor = new AnyRef
  def putIfAbsent(k: K,v: V): Option[String] = monitor.synchronized {
    underlying.get(k) match {
      case s: Some[V] => s
      case None =>
        underlying(k) = v
        None
    }
  }
  def remove(k: K, v: V): Boolean = monitor.synchronized {
    underlying.get(k) match {
      case Some(v0) if v == v0 => underlying.remove(k); true
      case None => false
    }
  }
  // etc.
}

Ответ 2

Если вы не хотите реализовать параллельную изменяемую хэш-карту самостоятельно, вы должны использовать scala.collection.concurrent.TrieMap.

Ответ 3

"Простым миксином", возможно, вы спрашиваете, можно ли использовать этот признак в качестве декоратора как показано здесь для SynchronizedMap, и ответ, по-видимому, отсутствует.

Реализации включают TrieMap и оболочку для Java ConcurrentMap (из которых две реализации). (Java также предлагает ConcurrentSkipListSet как Set.)

Также см. этот вопрос по вашему запросу.

Они вас затронули на стороне конверсии вещей, если это то, к чему вы привыкли:

scala> import java.util.concurrent._
import java.util.concurrent._

scala> import collection.JavaConverters._
import collection.JavaConverters._

scala> val m = new ConcurrentHashMap[String, Int]
m: java.util.concurrent.ConcurrentHashMap[String,Int] = {}

scala> val mm = m.asScala
mm: scala.collection.concurrent.Map[String,Int] = Map()

scala> mm.replace("five",5)
res0: Option[Int] = None

scala> mm.getClass
res1: Class[_ <: scala.collection.concurrent.Map[String,Int]] = class scala.collection.convert.Wrappers$JConcurrentMapWrapper