收藏我只是模拟的API在内存假的数据库,并使用scala.collection.mutable.HashMap[Int, AnyRef]
关于斯卡拉
即支持并发插入的最佳采集简单的问题?有更好的选择?
假设我需要另一种类似的集合,如
Map[Int, AnyRef]
,但这次键需要排序。 TreeMap是最佳选择吗?
在此先感谢
收藏我只是模拟的API在内存假的数据库,并使用scala.collection.mutable.HashMap[Int, AnyRef]
关于斯卡拉
即支持并发插入的最佳采集简单的问题?有更好的选择?
假设我需要另一种类似的集合,如Map[Int, AnyRef]
,但这次键需要排序。 TreeMap是最佳选择吗?
在此先感谢
你有两个选择这里。
您可以使用不可变的数据结构,如scala.collection.immutable.HashMap
,它提供了高效的不可变哈希映射。您还需要记住,每次更新此地图需要像这样进行同步:
object Database {
private var map = new immutable.HashMap[Int, AnyRef]
def get(index: Int) = map(index)
def insert(index: Int, value: AnyRef) =
synchronized(map = map.updated(index, value))
}
的另一种方法是使用并发可变的地图,像scala.collection.concurrent.TrieMap
,不需要额外的锁定:
object Database {
private val map = new concurrent.TrieMap[Int, AnyRef]
def get(index: Int) = map(index)
def insert(index: Int, value: AnyRef) = map.put(index, value)
}
即支持并行插入最好的收藏?有更好的选择?
使用一成不变的数据结构
TreeMap中是最好的选择?
是的。
直线前进的方式来实现线程安全是通过使用不可变的数据结构的 。
Scala提供了不可变的数据结构。只需导入scala.collection.immutable._
。
为了进行排序使用scala.collection.immutable.TreeMap
This post tells about how to use TreeMap and provide custom ordering
我不同意上面的建议。无论如何,如果你要有可变状态,你最好将它隔离到数据容器中,而不是每次都更换容器。
你最好用java容器来达到这个目的。对于hashmap,java ConcurrentHashMap
是您的最佳选择。对于一个被排序的实现,你就必须显式同步:
object DB {
import java.util._
val hashed = new concurrent.ConcurrentHashMap[String, AnyRef]
val sorted = Collections.synchronizedMap(new TreeMap[Int, AnyRef])
}
可以import scala.collection.JavaConversions._
隐式转换成那些地图阶,得到的好东西,像map
,filter
等等,但是... 你应该不是。在99%的案例中,使用其中的任何一个并不是一个好主意。除了常规的get
和put
(和put/computeIfNotExists
对于ConcurrentHashmap
的情况)之外的任何东西,实现起来都是不平凡的,并且使用起来很危险。
将这些看作是原始的键值容器,而不是全面的scala集合。
“如果你打算有无论如何,可变状态下,你最好在数据容器内部隔离它,而不是每次都更换容器本身。“你能详细说明原因吗?像HAMT这样的不可变结构并没有为一个变更制作所有数据的副本,只是其中的一小部分。另外,OP只需要创建最有可能用于测试目的的假/模拟数据库,所以在这里看起来性能并不重要。 – adamwy
我会补充说Scala的'scala.collection.concurrent.TrieMap'可能更具性能,因为它的所有操作都是无锁的,而Java'ConcurrentHashMap'似乎锁定put操作。 – adamwy
那么,除了性能(不可变集合确实比并发映射快一点),它在语义上就不那么透明了,而且更难推理,因为每当您更改整个“数据库”时就会更换它。如果某人碰巧保留了旧地图的引用,那么在将其替换为旧地图后,它将变为无效。如果两个更新同时发生并且不是原子的,那么必须将它们序列化,但是不可变映射的语义并没有明确说明它是必需的。 根据基准测试,'TrieMap'实际上比'ConcurrentHashMap'慢 – Dima
你是说在第一个例子中? ''var'在这里是必需的,因为你需要以某种方式更新'数据库'状态。 – adamwy
不要固定到具体的实现,除非你必须出于某些特定的原因:'map = Map.empty [Int,AnyRef]'或'map = SortedMap.empty [Int,AnyRef]' – Dima