在过去的几天里,做了一些竞争性的编程练习,我发现了一些问题的解决方案,而不是在 for
中在控制台中打印出文本。循环,他们构建了一个 StringBuilder
通过将文本相互附加。一开始我很困惑,但我尝试了一下并做了一些基准测试。
第一次测试:这是在屏幕上打印内容的经典方法:
class TestClass {
public static void main(String args[]) throws Exception {
double startTime = System.currentTimeMillis();
//code
for (int i = 0; i < 1000000; i++) {
System.out.print("test");
}
//code
double endTime = System.currentTimeMillis();
String result = String.format("for loop: %.5f", (endTime-startTime) / 1000);
System.out.print("\n"+result);
}
}
第二次测试:这是增强版,StringBuilder
:
class TestClass {
public static void main(String args[]) throws Exception {
double startTime = System.currentTimeMillis();
//code
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000000; i++) {
sb.append("test");
}
System.out.print(sb);
//code
double endTime = System.currentTimeMillis();
String result = String.format("for loop: %.5f", (endTime - startTime) / 1000);
System.out.print("\n" + result);
}
}
经过多次测试(使用Intel i5 6500四核3.2 GHZ CPU,Win 10运行),结果如下:
first test(for loop): 4,25s
second test(StringBuilder): 0.23s
结果并不意外,因为 out.print
是同步的,所以每次我们调用它时,都会增加一些开销。但慢了近 20 倍有点奇怪。
我的问题是:我们有办法进一步改进吗?
最佳答案
在这种情况下,不应归咎于
synchronized
关键字。
第一个测试用例很慢,因为System.out.print
会带来频繁的最小I/O。
你可以使用BufferedWriter
(它的write方法也是同步的)来减少不必要的I/O:
BufferedWriter log = new BufferedWriter(new OutputStreamWriter(System.out));
//code
for (int i = 0; i < 1000000; i++) {
log.write("test");
}
for loop: 0.21200
<小时/>
并且,StringBuilder
在内部使用byte[]
进行字符存储。当您通过将旧值复制到新的 byte[]
中不断追加内容时,该字节数组将会增长。
给它足够大的容量可能会带来一些效率:
StringBuilder sb = new StringBuilder(1000000 * 10);
关于Java System.out.print 效率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51990047/