【问题标题】:Is multiple assignment of tuples slower than multiple assignment statements?元组的多重赋值比多重赋值语句慢吗?
【发布时间】:2014-09-22 17:29:19
【问题描述】:

使用元组分配多个变量和在多个语句中分配它们有区别吗?

比如下面的代码sn-ps有区别吗?

// multiple assignment using tuples
val (x, y) = (str.length, str.substring(1, 2))

// multiple-statement assignment
val x = str.length
val y = str.substring(1, 2)

【问题讨论】:

    标签: scala syntax microbenchmark


    【解决方案1】:

    不同。使用元组的方法实际上是调用一个提取器(unapply 方法),这会在运行时产生成本。第二种方法肯定更快。

    为了了解不同之处,这里是对两种方法的反编译,显示了这两种方法。您可以清楚地看到第一种方法如何导致更多的操作。

    这里要注意的重要一点是,第一个表达式需要自动装箱到java.lang.Integer(因为Tuple2 接受对象),而第二个表达式使用没有装箱的值。

      public void m1(java.lang.String);
        Code:
           0: new           #16                 // class scala/Tuple2
           3: dup           
           4: aload_1       
           5: invokevirtual #22                 // Method java/lang/String.length:()I
           8: invokestatic  #28                 // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
          11: aload_1       
          12: iconst_1      
          13: iconst_2      
          14: invokevirtual #32                 // Method java/lang/String.substring:(II)Ljava/lang/String;
          17: invokespecial #35                 // Method scala/Tuple2."<init>":(Ljava/lang/Object;Ljava/lang/Object;)V
          20: astore_3      
          21: aload_3       
          22: ifnull        75
          25: aload_3       
          26: invokevirtual #38                 // Method scala/Tuple2._1$mcI$sp:()I
          29: istore        4
          31: aload_3       
          32: invokevirtual #42                 // Method scala/Tuple2._2:()Ljava/lang/Object;
          35: checkcast     #18                 // class java/lang/String
          38: astore        5
          40: new           #16                 // class scala/Tuple2
          43: dup           
          44: iload         4
          46: invokestatic  #28                 // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
          49: aload         5
          51: invokespecial #35                 // Method scala/Tuple2."<init>":(Ljava/lang/Object;Ljava/lang/Object;)V
          54: astore        6
          56: aload         6
          58: astore_2      
          59: aload_2       
          60: invokevirtual #38                 // Method scala/Tuple2._1$mcI$sp:()I
          63: istore        7
          65: aload_2       
          66: invokevirtual #42                 // Method scala/Tuple2._2:()Ljava/lang/Object;
          69: checkcast     #18                 // class java/lang/String
          72: astore        8
          74: return        
          75: new           #44                 // class scala/MatchError
          78: dup           
          79: aload_3       
          80: invokespecial #47                 // Method scala/MatchError."<init>":(Ljava/lang/Object;)V
          83: athrow        
    
      public void m2(java.lang.String);
        Code:
           0: aload_1       
           1: invokevirtual #22                 // Method java/lang/String.length:()I
           4: istore_2      
           5: aload_1       
           6: iconst_1      
           7: iconst_2      
           8: invokevirtual #32                 // Method java/lang/String.substring:(II)Ljava/lang/String;
          11: astore_3      
          12: return        
    }
    

    【讨论】:

    • 字节码不能说明全部。你必须看看 JVM 优化器对那个东西做了什么。它很可能能够完全优化它。这并不难:Scala.js 优化器可以做到这一点,所以如果 JVM 也能做到,我不会感到惊讶。
    • @sjrd 感谢您的来信。 JVM 可能会优化其中的一部分。在调用该行 10000 次后,它应该能够摆脱 throw 指令,也许也可以摆脱演员阵容。但是请注意,我没有提到存在性能差异。我必须测量它才能这么说。我只是从理论角度指出差异,帮助人们更好地理解 Scala 的工作原理,揭示编译器对我们隐藏的东西。
    • 对不起,我说我没有提到性能,但我确实提到了。实际上,我不认为 JVM 可以优化整个表达式。 Scala.js 应该能够在编译阶段做到这一点。但由于 Scala 编译器没有这样做,我认为 JVM 不会省略分配对象和装箱值的指令。请查看我关于拳击的更新。
    • Scala.js 优化器在链接阶段执行此操作,具有整个程序知识,并且没有关于元组或任何东西的特殊知识(仅相当标准的优化)。理论上,JVM 拥有所有必要的信息。通过内联和标量替换(JVM 所做的)等优化,可以消除整个事情(甚至是盒子,因为它们在内联后不会逃脱方法)。但是,是的,再一次,这就是理论。我并不是说 JVM 实际上消除了它。只是说可以
    猜你喜欢
    • 1970-01-01
    • 2011-07-08
    • 2011-01-23
    • 1970-01-01
    • 1970-01-01
    • 2021-03-30
    • 2011-10-31
    • 2016-03-05
    相关资源
    最近更新 更多