dea*_*mon 16 performance scala
JVM优化字符串连接,+并用a替换它StringBuilder.这在Scala中应该是相同的.但是如果串连接会发生什么++=?
var x = "x"
x ++= "y"
x ++= "z"
Run Code Online (Sandbox Code Playgroud)
据我所知,这个方法处理像char seqences这样的字符串,所以即使JVM创建StringBuilder它也会导致很多方法调用,对吧?使用StringBuilder会更好吗?
隐式转换的字符串是什么类型的?
Rex*_*err 14
有一个巨大的巨大及时采取差异.
如果使用重复添加字符串+=,则不要优化O(n^2)创建增量更长的字符串的成本.因此,对于添加一个或两个,您将看不到差异,但它不会扩展; 当你添加100(短)字符串时,使用StringBuilder的速度要快20倍.(精确数据:1.3 us对27.1我们添加数字0到100的字符串表示;时间应该可以重现到约+ = 5%,当然也适用于我的机器.)
使用++=上var String又是远差远了,因为你然后指示斯卡拉治疗字符串作为一个字符一个字符集合,然后需要各种包装,使字符串看起来像一个集合(包括盒装字符一个字符另外使用通用版本++!).现在你再增加100倍就会慢16倍!(准确的数据:428.8 us用于++=var字符串而不是+=26.7 us.)
如果你用一堆+es 编写一个单独的语句,那么Scala编译器将使用一个StringBuilder并最终得到一个有效的结果(Data:1.8 us on非常量字符串从数组中拉出).
因此,如果您添加除了+行之外的任何字符串,并且您关心效率,请使用StringBuilder.绝对不要用++=另一个添加String到var String; 没有任何理由这样做,并且有很大的运行时间惩罚.
(注意 - 通常你根本不在乎你的字符串添加效率如何!StringBuilder除非你有理由怀疑这个特定的代码路径被大量调用,否则不要用额外的s 混乱你的代码.)
som*_*ytt 13
实际上,不方便的事实StringOps通常仍然是一个分配:
scala> :pa
// Entering paste mode (ctrl-D to finish)
class Concat {
var x = "x"
x ++= "y"
x ++= "z"
}
// Exiting paste mode, now interpreting.
defined class Concat
scala> :javap -prv Concat
Binary file Concat contains $line3.$read$$iw$$iw$Concat
Size 1211 bytes
MD5 checksum 1900522728cbb0ed0b1d3f8b962667ad
Compiled from "<console>"
public class $line3.$read$$iw$$iw$Concat
SourceFile: "<console>"
[snip]
public $line3.$read$$iw$$iw$Concat();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=6, locals=1, args_size=1
0: aload_0
1: invokespecial #19 // Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #20 // String x
7: putfield #10 // Field x:Ljava/lang/String;
10: aload_0
11: new #22 // class scala/collection/immutable/StringOps
14: dup
15: getstatic #28 // Field scala/Predef$.MODULE$:Lscala/Predef$;
18: aload_0
19: invokevirtual #30 // Method x:()Ljava/lang/String;
22: invokevirtual #34 // Method scala/Predef$.augmentString:(Ljava/lang/String;)Ljava/lang/String;
25: invokespecial #36 // Method scala/collection/immutable/StringOps."<init>":(Ljava/lang/String;)V
28: new #22 // class scala/collection/immutable/StringOps
31: dup
32: getstatic #28 // Field scala/Predef$.MODULE$:Lscala/Predef$;
35: ldc #38 // String y
37: invokevirtual #34 // Method scala/Predef$.augmentString:(Ljava/lang/String;)Ljava/lang/String;
40: invokespecial #36 // Method scala/collection/immutable/StringOps."<init>":(Ljava/lang/String;)V
43: getstatic #28 // Field scala/Predef$.MODULE$:Lscala/Predef$;
46: invokevirtual #42 // Method scala/Predef$.StringCanBuildFrom:()Lscala/collection/generic/CanBuildFrom;
49: invokevirtual #46 // Method scala/collection/immutable/StringOps.$plus$plus:(Lscala/collection/GenTraversableOnce;Lscala/collection/generic/CanBuildFrom;)Ljava/lang/Object;
52: checkcast #48 // class java/lang/String
55: invokevirtual #50 // Method x_$eq:(Ljava/lang/String;)V
Run Code Online (Sandbox Code Playgroud)
在此答案中查看更多演示.
编辑:更多的说,你在每次重新分配时都在构建String,所以,不,你没有使用单个StringBuilder.
但是,优化是由javacJIT编译器完成的,而不是JIT编译器,因此要比较同类的果实:
public class Strcat {
public String strcat(String s) {
String t = " hi ";
String u = " by ";
return s + t + u; // OK
}
public String strcat2(String s) {
String t = s + " hi ";
String u = t + " by ";
return u; // bad
}
}
Run Code Online (Sandbox Code Playgroud)
而
$ scala
Welcome to Scala version 2.11.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_11).
Type in expressions to have them evaluated.
Type :help for more information.
scala> :se -Xprint:typer
scala> class K { def f(s: String, t: String, u: String) = s ++ t ++ u }
[[syntax trees at end of typer]] // <console>
def f(s: String, t: String, u: String): String = scala.this.Predef.augmentString(scala.this.Predef.augmentString(s).++[Char, String](scala.this.Predef.augmentString(t))(scala.this.Predef.StringCanBuildFrom)).++[Char, String](scala.this.Predef.augmentString(u))(scala.this.Predef.StringCanBuildFrom)
Run Code Online (Sandbox Code Playgroud)
不好.或者更糟糕的是,要展开雷克斯的解释:
"abc" ++ "def"
augmentString("abc").++[Char, String](augmentString("def"))(StringCanBuildFrom)
collection.mutable.StringBuilder.newBuilder ++= new WrappedString(augmentString("def"))
val b = collection.mutable.StringBuilder.newBuilder
new WrappedString(augmentString("def")) foreach b.+=
Run Code Online (Sandbox Code Playgroud)
正如雷克斯所解释的那样,但是StringBuilder覆盖++=(String)但不是Growable.++=(Traversable[Char]).
万一你想知道是什么unaugmentString:
28: invokevirtual #40 // Method scala/Predef$.augmentString:(Ljava/lang/String;)Ljava/lang/String;
31: invokevirtual #43 // Method scala/Predef$.unaugmentString:(Ljava/lang/String;)Ljava/lang/String;
34: invokespecial #46 // Method scala/collection/immutable/WrappedString."<init>":(Ljava/lang/String;)V
Run Code Online (Sandbox Code Playgroud)
并且只是为了表明你最后打电话,+=(Char)但拳击和拆箱之后:
public final scala.collection.mutable.StringBuilder apply(char);
flags: ACC_PUBLIC, ACC_FINAL
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: getfield #19 // Field b$1:Lscala/collection/mutable/StringBuilder;
4: iload_1
5: invokevirtual #24 // Method scala/collection/mutable/StringBuilder.$plus$eq:(C)Lscala/collection/mutable/StringBuilder;
8: areturn
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 this L$line10/$read$$iw$$iw$$anonfun$1;
0 9 1 x C
LineNumberTable:
line 9: 0
public final java.lang.Object apply(java.lang.Object);
flags: ACC_PUBLIC, ACC_FINAL, ACC_BRIDGE, ACC_SYNTHETIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: invokestatic #35 // Method scala/runtime/BoxesRunTime.unboxToChar:(Ljava/lang/Object;)C
5: invokevirtual #37 // Method apply:(C)Lscala/collection/mutable/StringBuilder;
8: areturn
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 this L$line10/$read$$iw$$iw$$anonfun$1;
0 9 1 v1 Ljava/lang/Object;
LineNumberTable:
line 9: 0
Run Code Online (Sandbox Code Playgroud)
一个好笑会让一些氧气进入血液.
| 归档时间: |
|
| 查看次数: |
13800 次 |
| 最近记录: |