如何避免在需要 Map[Number, String] 的地方传递 Map[Integer, String] 的开销?
问题: 我有一个 mutable.Map[Integer, String],我想将其传递给两个方法:
- def processNumbers(nums: Map[Number, String])
- def processIntegers(nums: mutable.Map[Integer, String])
编译后错误,我最终得到了这个:
val ints: mutable.Map[Integer, String] = mutable.Map.empty[Integer, String]
//init of ints
val nums: Map[Number, String] = ints.toMap[Number, String]
processNumbers(nums)
processIntegers(ints)
通过一个小实验,我发现我的做法有很大的开销:类型转换步骤乘以 10 执行时间。
总而言之,类型转换实际上只是为了取悦编译器,那么如何在没有任何开销的情况下做到这一点呢?
有关信息,我的实验代码:
package qndTests
import scala.collection.mutable
object TypeTest {
var hashNums = 0
var hashIntegers = 0
def processNumbers(nums: Map[Number, String]): Unit = {
nums.foreach(num =>{
hashNums+=num._1.hashCode+num._2.hashCode
})
}
def processNumbers2(nums: mutable.Map[Integer, String]): Unit = {
nums.foreach(num =>{
hashNums+=num._1.hashCode+num._2.hashCode
})
}
def processIntegers(nums: mutable.Map[Integer, String]): Unit = {
nums.foreach(num =>{
hashIntegers+=num._1.hashCode+num._2.hashCode
})
}
def test(ints: mutable.Map[Integer, String], convertType: Boolean): Unit = {
if(convertType)
println("run test with type conversion")
else
println("run test without type conversion")
val start = System.nanoTime
hashNums = 0
hashIntegers = 0
val nTest = 10
for(i <- 0 to nTest) {
if(convertType){
val nums: Map[Number, String] = ints.toMap[Number, String] //how much does that cost ?
processNumbers(nums)
}else{
processNumbers2(ints)
}
processIntegers(ints)
}
val end= System.nanoTime
println("nums: "+hashNums)
println("ints: "+hashIntegers)
println(end-start)
}
def main(args: Array[String]): Unit = {
val ints: mutable.Map[Integer, String] = mutable.Map.empty[Integer, String]
val testSize = 1000000
println("creating a map of "+testSize+" elements")
for(i <- 0 to testSize) ints.put(i, i.toBinaryString)
println("done")
test(ints, false)
test(ints, true)
}
}
及其输出:
创建 1000000 个元素的映射
完成
无需类型转换即可运行测试
数字:-1650117013
整数:-1650117013
2097538520
使用类型转换运行测试
数字:-1650117013
整数:-1650117013
25423803480
-->第一种情况大约需要 2 秒,而第二种情况大约需要 25 秒!
The problem:
I have a mutable.Map[Integer, String], I want to pass it to two methods:
- def processNumbers(nums: Map[Number, String])
- def processIntegers(nums: mutable.Map[Integer, String])
after getting compile error, I ended up with this:
val ints: mutable.Map[Integer, String] = mutable.Map.empty[Integer, String]
//init of ints
val nums: Map[Number, String] = ints.toMap[Number, String]
processNumbers(nums)
processIntegers(ints)
With a little experiment, I figured out that my way of doing this has a significant overhead: the type conversion step multiply by 10 the execution time.
All in all the type conversion is really just to please the compiler, so how to do that without any overhead ?
For info, the code of my experiment:
package qndTests
import scala.collection.mutable
object TypeTest {
var hashNums = 0
var hashIntegers = 0
def processNumbers(nums: Map[Number, String]): Unit = {
nums.foreach(num =>{
hashNums+=num._1.hashCode+num._2.hashCode
})
}
def processNumbers2(nums: mutable.Map[Integer, String]): Unit = {
nums.foreach(num =>{
hashNums+=num._1.hashCode+num._2.hashCode
})
}
def processIntegers(nums: mutable.Map[Integer, String]): Unit = {
nums.foreach(num =>{
hashIntegers+=num._1.hashCode+num._2.hashCode
})
}
def test(ints: mutable.Map[Integer, String], convertType: Boolean): Unit = {
if(convertType)
println("run test with type conversion")
else
println("run test without type conversion")
val start = System.nanoTime
hashNums = 0
hashIntegers = 0
val nTest = 10
for(i <- 0 to nTest) {
if(convertType){
val nums: Map[Number, String] = ints.toMap[Number, String] //how much does that cost ?
processNumbers(nums)
}else{
processNumbers2(ints)
}
processIntegers(ints)
}
val end= System.nanoTime
println("nums: "+hashNums)
println("ints: "+hashIntegers)
println(end-start)
}
def main(args: Array[String]): Unit = {
val ints: mutable.Map[Integer, String] = mutable.Map.empty[Integer, String]
val testSize = 1000000
println("creating a map of "+testSize+" elements")
for(i <- 0 to testSize) ints.put(i, i.toBinaryString)
println("done")
test(ints, false)
test(ints, true)
}
}
and its output:
creating a map of 1000000 elements
done
run test without type conversion
nums: -1650117013
ints: -1650117013
2097538520
run test with type conversion
nums: -1650117013
ints: -1650117013
25423803480
--> about 2 seconds in the first case against 25 seconds in the second one !
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
正如您所看到的,
Map[A,B]
在键类型A
中是不变的,因此您需要某种类型的转换来分配给变量输入Map[A,B]
aMap[A1,B]
,其中A1 <: A
。但是,如果您可以更改 def processNumbers(nums: Map[Number, String]) 的定义,您可以尝试以下操作:并传递 Map[Integer, String] 无需转换。
这有助于解决您的问题吗?
As you've seen,
Map[A,B]
is nonvariant in the key typeA
, so you'll need a conversion of some kind to assign to a variable of typeMap[A,B]
aMap[A1,B]
whereA1 <: A
. However, if you can change the definition ofdef processNumbers(nums: Map[Number, String])
, you could try something like:and pass the
Map[Integer, String]
without conversion.Would that help solve your problem?