如何避免传递Map [Integer,String]的开销,其中Map [Number,String]是预期的?

时间:2011-05-07 10:28:12

标签: performance scala collections types map

问题: 我有一个mutable.Map [Integer,String],我想把它传递给两个方法:

  1. def processNumbers(nums:Map [Number,String])
  2. def processIntegers(nums:mutable.Map [Integer,String])
  3. 收到编译错误后,我最终得到了这个:

    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个元素的地图
    做过
    没有类型转换的运行测试
    nums:-1650117013
    整数:-1650117013
    2097538520个
    用类型转换运行测试
    nums:-1650117013
    整数:-1650117013
    25423803480

    - &GT;在第一种情况下大约2秒,在第二种情况下反对25秒!

1 个答案:

答案 0 :(得分:3)

正如您所见,Map[A,B]在密钥类型A中是非变量的,因此您需要某种转换才能分配给Map[A,B]类型的变量a { {1}} Map[A1,B]。但是,如果您可以更改A1 <: A的定义,则可以尝试以下内容:

def processNumbers(nums: Map[Number, String])

并传递def processNumbers[T <: Number](nums: Map[T, String]) 而不进行转换。

这有助于解决您的问题吗?