原文:Why is printing "B" dramatically slower than printing "#"?
问题:
cнŝdk:
我创建了两个 1000 x 1000 的矩阵:
第一个的矩阵元素是:O 和 #,
第二个的矩阵元素是:O 和 B。
用下面的代码打印,第一个矩阵运行了 8.52 秒:
Random r = new Random();
for (int i = 0; i < 1000; i++) {
for (int j = 0; j < 1000; j++) {
if(r.nextInt(4) == 0) {
System.out.print("O");
} else {
System.out.print("#");
}
}
System.out.println("");
}
而用下面的代码,打印第二个矩阵运行了 259.152 秒:
Random r = new Random();
for (int i = 0; i < 1000; i++) {
for (int j = 0; j < 1000; j++) {
if(r.nextInt(4) == 0) {
System.out.print("O");
} else {
System.out.print("B"); //only line changed
}
}
System.out.println("");
}
为什么这么“抓马”(dramatically),两次打印矩阵的时间差距这么大?
回答:
T.J. Crowder:
纯猜测:你正用一个终端打印矩阵,这个终端尝试识别单词以自适应换行(word-wrapping)而非识别字符(character-wrapping),并将字符 B 识别为某个单词的字符,将字符 # 视为非单词字符。因此,当到达某一行的行尾,终端会搜索一处来断开这行,当它看到字符 #,会愉快地从那里断开;而对于字符 B,终端需要更长的时间搜索,并且可能有更多的文本需要包装(这一操作在一些终端上可能是很耗时的,例如,终端需要退格,然后输出空格覆盖那些被换行的字符)。
但以上只是推测哈。
补充:
T.J. Crowder:
System.out.println 本身并不会自动换行;但它的输出对象(终端)正在进行自动换行(和阻塞,所以 System.out.println 必须等待)。
Bob Kerns:
精彩的推理。我们应该从这一课中总结出:在测试性能时,应该不使用输出,或应该将输出定向到 /dev/null(Windows 上为 NUL),或者至少将输出定向到一个文件。即使不像这个问题这么令人困惑,在任何类型的控制台(Console)上输出都会有非常昂贵的 IO 消耗,并且总会扭曲时序。