Jac*_*ack 10 java groovy scala bytecode
我用的Java像6-7岁,然后在几个月前,我发现Groovy中,并开始节省大量的输入..然后我不知道某些事情如何引擎盖下工作(因为常规的表现真的很差),并了解,给你动态类型每一个Groovy的对象是MetaClass处理所有的JVM不能由自己来处理事情的对象.当然,这会在您编写的内容和执行的内容之间引入一层,从而减慢所有内容.
然后有一天我开始得到一些关于Scala的信息.这两种语言在字节码翻译中的比较如何?他们添加到普通Java代码可以获得的正常结构中有多少东西?
我的意思是,Scala是静态类型的,因此Java类的包装应该更轻,因为在编译期间会检查很多东西,但我不确定内部存在的真正差异.(我不是在谈论Scala的功能方面与其他方面相比,这是另一回事)
有人可以开导我吗?
从WizardOfOdds评论好像是得到更少的输入和相同性能的唯一方法是写在翻译的东西中间翻译的Java代码(让的javac编译)不alterating事情是如何执行的,只是增加synctatic糖全无关心语言本身的其他后备.
ret*_*nym 23
Scala在降低抽象成本方面做得越来越好.
在代码中的内联注释中,我解释了数组访问,pimped类型,结构类型以及对基元和对象进行抽象的性能特征.
object test {
/**
* From the perspective of the Scala Language, there isn't a distinction between
* objects, primitives, and arrays. They are all unified under a single type system,
* with Any as the top type.
*
* Array access, from a language perspective, looks like a.apply(0), or a.update(0, 1)
* But this is compiled to efficient bytecode without method calls.
*/
def accessPrimitiveArray {
val a = Array.fill[Int](2, 2)(1)
a(0)(1) = a(1)(0)
}
// 0: getstatic #62; //Field scala/Array$.MODULE$:Lscala/Array$;
// 3: iconst_2
// 4: iconst_2
// 5: new #64; //class test$$anonfun$1
// 8: dup
// 9: invokespecial #65; //Method test$$anonfun$1."<init>":()V
// 12: getstatic #70; //Field scala/reflect/Manifest$.MODULE$:Lscala/reflect/Manifest$;
// 15: invokevirtual #74; //Method scala/reflect/Manifest$.Int:()Lscala/reflect/AnyValManifest;
// 18: invokevirtual #78; //Method scala/Array$.fill:(IILscala/Function0;Lscala/reflect/ClassManifest;)[Ljava/lang/Object;
// 21: checkcast #80; //class "[[I"
// 24: astore_1
// 25: aload_1
// 26: iconst_0
// 27: aaload
// 28: iconst_1
// 29: aload_1
// 30: iconst_1
// 31: aaload
// 32: iconst_0
// 33: iaload
// 34: iastore
// 35: return
Run Code Online (Sandbox Code Playgroud)
/**
* Rather than dynamically adding methods to a meta-class, Scala
* allows values to be implicity converted. The conversion is
* fixed at compilation time. At runtime, there is an overhead to
* instantiate RichAny before foo is called. HotSpot may be able to
* eliminate this overhead, and future versions of Scala may do so
* in the compiler.
*/
def callPimpedMethod {
class RichAny(a: Any) {
def foo = 0
}
implicit def ToRichAny(a: Any) = new RichAny(a)
new {}.foo
}
// 0: aload_0
// 1: new #85; //class test$$anon$1
// 4: dup
// 5: invokespecial #86; //Method test$$anon$1."<init>":()V
// 8: invokespecial #90; //Method ToRichAny$1:(Ljava/lang/Object;)Ltest$RichAny$1;
// 11: invokevirtual #96; //Method test$RichAny$1.foo:()I
// 14: pop
// 15: return
Run Code Online (Sandbox Code Playgroud)
/**
* Scala allows 'Structural Types', which let you have a compiler-checked version
* of 'Duck Typing'. In Scala 2.7, the invocation of .size was done with reflection.
* In 2.8, the Method object is looked up on first invocation, and cached for later
* invocations..
*/
def duckType {
val al = new java.util.ArrayList[AnyRef]
(al: { def size(): Int }).size()
}
// [snip]
// 13: invokevirtual #106; //Method java/lang/Object.getClass:()Ljava/lang/Class;
// 16: invokestatic #108; //Method reflMethod$Method1:(Ljava/lang/Class;)Ljava/lang/reflect/Method;
// 19: aload_2
// 20: iconst_0
// 21: anewarray #102; //class java/lang/Object
// 24: invokevirtual #114; //Method java/lang/reflect/Method.invoke:(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;
// 27: astore_3
// 28: aload_3
// 29: checkcast #116; //class java/lang/Integer
Run Code Online (Sandbox Code Playgroud)
/**
* Scala 2.8 introduces annotation driven specialization of methods and classes. This avoids
* boxing of primitives, at the cost of increased code size. It is planned to specialize some classes
* in the standard library, notable Function1.
*
* The type parameter T in echoSpecialized is annotated to instruct the compiler to generated a specialized version
* for T = Int.
*/
def callEcho {
echo(1)
echoSpecialized(1)
}
// public void callEcho();
// Code:
// Stack=2, Locals=1, Args_size=1
// 0: aload_0
// 1: iconst_1
// 2: invokestatic #134; //Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
// 5: invokevirtual #138; //Method echo:(Ljava/lang/Object;)Ljava/lang/Object;
// 8: pop
// 9: aload_0
// 10: iconst_1
// 11: invokevirtual #142; //Method echoSpecialized$mIc$sp:(I)I
// 14: pop
// 15: return
def echo[T](t: T): T = t
def echoSpecialized[@specialized("Int") T](t: T): T = t
}
Run Code Online (Sandbox Code Playgroud)
Scala中for被转换为调用高阶函数的链:foreach,map,flatMap和withFilter.这非常强大,但您需要注意以下代码与Java中的类似外观构造的效率差不多.斯卡拉2.8将@specialize功能1,至少Double和Int,并希望也将@specialize Traversable#foreach,这将至少除去拳击成本.
for-comprehension的主体作为闭包传递,它被编译为匿名内部类.
def simpleForLoop {
var x = 0
for (i <- 0 until 10) x + i
}
// public final int apply(int);
// 0: aload_0
// 1: getfield #18; //Field x$1:Lscala/runtime/IntRef;
// 4: getfield #24; //Field scala/runtime/IntRef.elem:I
// 7: iload_1
// 8: iadd
// 9: ireturn
// public final java.lang.Object apply(java.lang.Object);
// 0: aload_0
// 1: aload_1
// 2: invokestatic #35; //Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
// 5: invokevirtual #37; //Method apply:(I)I
// 8: invokestatic #41; //Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
// 11: areturn
// public test$$anonfun$simpleForLoop$1(scala.runtime.IntRef);
// 0: aload_0
// 1: aload_1
// 2: putfield #18; //Field x$1:Lscala/runtime/IntRef;
// 5: aload_0
// 6: invokespecial #49; //Method scala/runtime/AbstractFunction1."<init>":()V
// 9: return
Run Code Online (Sandbox Code Playgroud)
LineNumberTable:第4行:0
// 0: new #16; //class scala/runtime/IntRef
// 3: dup
// 4: iconst_0
// 5: invokespecial #20; //Method scala/runtime/IntRef."<init>":(I)V
// 8: astore_1
// 9: getstatic #25; //Field scala/Predef$.MODULE$:Lscala/Predef$;
// 12: iconst_0
// 13: invokevirtual #29; //Method scala/Predef$.intWrapper:(I)Lscala/runtime/RichInt;
// 16: ldc #30; //int 10
// 18: invokevirtual #36; //Method scala/runtime/RichInt.until:(I)Lscala/collection/immutable/Range$ByOne;
// 21: new #38; //class test$$anonfun$simpleForLoop$1
// 24: dup
// 25: aload_1
// 26: invokespecial #41; //Method test$$anonfun$simpleForLoop$1."<init>":(Lscala/runtime/IntRef;)V
// 29: invokeinterface #47, 2; //InterfaceMethod scala/collection/immutable/Range$ByOne.foreach:(Lscala/Function1;)V
// 34: return
Run Code Online (Sandbox Code Playgroud)
Dan*_*ral 10
很多好的答案,我会尝试添加我从你的问题中得到的其他东西.有没有斯卡拉对象的包装.例如,以下两个类(分别在Scala和Java中)生成完全相同的字节码:
// This is Scala
class Counter {
private var x = 0
def getCount() = {
val y = x
x += 1
y
}
}
// This is Java
class Counter {
private int x = 0;
private int x() {
return x;
}
private void x_$eq(int x) {
this.x = x;
}
public int getCounter() {
int y = x();
x_$eq(x() + 1);
return y;
}
}
Run Code Online (Sandbox Code Playgroud)
特别值得注意的是,Scala总是通过getter和setter进入字段,甚至是同一类的其他方法.然而,重点是这里绝对没有类包装.无论是用Java还是Scala编译都是一样的.
现在,Scala可以更轻松地编写更慢的代码.它的一些例子是:
for只是增加索引时Scala的速度明显慢于Java - 到目前为止,解决方案是使用while循环,尽管有人编写了一个自动执行转换的编译器插件.迟早会增加这样的优化.
在Scala中编写闭包和传递函数非常容易.它使代码更具可读性,但它比在紧密循环中不执行它慢得多.
它也很容易参数化,以便人们可以传递Int,如果你正在处理原语(在Scala,AnyVal子类中),这可能会导致性能不佳.
下面是一个用Scala以两种不同的方式编写的类的示例,其中更紧凑的类是慢两倍:
class Hamming extends Iterator[BigInt] {
import scala.collection.mutable.Queue
val qs = Seq.fill(3)(new Queue[BigInt])
def enqueue(n: BigInt) = qs zip Seq(2, 3, 5) foreach { case (q, m) => q enqueue n * m }
def next = {
val n = qs map (_.head) min;
qs foreach { q => if (q.head == n) q.dequeue }
enqueue(n)
n
}
def hasNext = true
qs foreach (_ enqueue 1)
}
class Hamming extends Iterator[BigInt] {
import scala.collection.mutable.Queue
val q2 = new Queue[BigInt]
val q3 = new Queue[BigInt]
val q5 = new Queue[BigInt]
def enqueue(n: BigInt) = {
q2 enqueue n * 2
q3 enqueue n * 3
q5 enqueue n * 5
}
def next = {
val n = q2.head min q3.head min q5.head
if (q2.head == n) q2.dequeue
if (q3.head == n) q3.dequeue
if (q5.head == n) q5.dequeue
enqueue(n)
n
}
def hasNext = true
List(q2, q3, q5) foreach (_ enqueue 1)
}
Run Code Online (Sandbox Code Playgroud)
这也是在需要时如何完全平衡性能的一个很好的例子.例如,更快的版本foreach在构造函数中使用,它不会导致性能问题.
最后,这都是透视问题.在对象上调用方法比直接调用函数和过程要慢,这是面向对象编程的一个主要反对意见,但事实证明它在大多数情况下都不是问题.
您可以将Java音译为Scala,最终得到几乎完全相同的字节码.因此Scala完全能够像Java一样快.
也就是说,有很多方法可以编写速度更慢,内存更密集的Scala代码,这些代码比Java等效代码更短,更易读.这很好!我们使用Java而不是C,因为内存保护可以改进我们的代码.Scala的额外表现力意味着你可以编写更短的程序,而不是像Java那样更笨拙的程序.有时会伤害性能,但大部分时间都没有.
反义词和David已经涵盖了关于Scala的要点:它基本上和Java一样快,并且它是这样的,因为它是静态类型的(因此不需要额外的运行时检查)并使用JVM通常可以完全删除的轻量包装器.
Scala确实很容易使用强大的通用库功能.与Java中任何强大的通用库一样,它具有一些与之相关的性能损失.例如,使用java.util.HashMap在字节和字节之间实现映射在Java中会非常缓慢(与原始数组查找表相比),并且在Scala中同样会很慢.但Scala为您提供了更多此类功能,并且可以非常轻松地调用它们,以至于您可以在非常少的代码中完成大量工作.和往常一样,当你很容易提出要求时,人们有时会要求很多,然后想知道为什么需要这么长时间.(当人们在幕后学习(或仔细思考)必须发生的事情时,易于询问会让人更加惊讶.)
可能引起的唯一合理批评是Scala并没有像编写高性能代码那样容易.大多数易于使用的功能都针对通用函数编程,它仍然非常快,但不如直接访问原始类型那么快.例如,Scala有一个非常强大的for循环,但是它使用泛型类型,因此必须将原语装箱,因此你不能有效地使用它来迭代原始数组; 你必须使用while循环代替.(性能差异很可能会在2.8中减少,因为提到了反义词.)
| 归档时间: |
|
| 查看次数: |
3273 次 |
| 最近记录: |