Why is printing “B” dramatically slower than printing “#”?
我生成了两个1000x 1000矩阵:
第一矩阵:O和#。第二矩阵:O和B。
使用以下代码,第一个矩阵需要8.52秒完成:
1 2 3 4 5 6 7 8 9 10 11 12
| 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秒完成:
1 2 3 4 5 6 7 8 9 10 11 12
| 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("");
} |
为什么运行时间会大不相同?
如评论所示,仅打印System.out.print("#");需要7.8871秒,而System.out.print("B");则需要still printing...秒。
正如其他人指出的那样,这对他们来说是正常的,例如,我尝试了ideone.com,两段代码以相同的速度执行。
试验条件:
- 我从NetBeans 7.2运行了这个测试,并将输出放到它的控制台中。
- 我用System.nanoTime()来测量
- 尝试更改rand.nextint(4)==0到i<250以消除随机生成器的影响。你可能会耗尽熵,减慢随机产生的速度。
- 两人在我的机器上运行的时间似乎相同,~4秒。
- @然后分支预测将开始。把rand.nextInt(4)==0改为i%4==0会更好(在避免分支预测加速进程方面)。
- 如果您建议打印b比打印花费更多时间,为什么不尝试打印所有b&all,而不是依赖随机变量r?
- 在三次试验中(B’vs’"),我的时间在36到38秒之间(四舍五入)。我添加了starttime和endtime字段,在循环前后获取system.currentTimeMillis作为计时依据。我建议您在本地有一些问题(运行时引擎、处理器、黑色直升机)。
- 根据接受的答案,显然您没有尝试运行它,将输出重定向到文件或/dev/null。
- @fejese,random()不是密码RNG,因此不会耗尽熵池。
- 矩阵,@francescomenzani?在我看来,这毫无意义;是让问题不容易找到,不描述它的范围更好,只是增加了噪音。
- @palac我找不到任何特定于System.out的打印标签,但我认为system.out本身可以很好地代表这个问题。
- 我尝试在系统上运行相同的代码。在20次试验中,打印""代码比打印"B"慢3-5倍。
纯粹的猜测是,您使用的是一个终端,它尝试进行单词包装而不是字符包装,并将B视为单词字符,而将#视为非单词字符。因此,当它到达一行的末尾并搜索一个断开该行的位置时,它几乎立即看到一个#,并很高兴地断开了该行;而对于B,它必须继续搜索更长的时间,并且可能有更多的文本需要包装(在某些终端上,例如,输出退格,然后输出空间到把包裹好的信写下来)。
但这纯粹是猜测。
- 这实际上是正确的答案!在B之后添加一个空间可以解决这个问题。
- 有些答案来自于刻苦学习的经验。T.J.和我(因为我们是朋友)在苹果和ZX80/81时代长大。当时没有内置的自动换行。所以我们都写了自己的-不止一次。这些教训会一直伴随着你,它们会被你的蜥蜴大脑灼伤。但是,如果在这之后您倾向于使用代码,当您的环境字包装所有内容时,或者在运行时之前手动执行时,就很难遇到换行的问题。
- 精彩演绎。但是,我们应该从本课中归纳出来,并始终在消除输出、指向/dev/null(在Windows上为nul)或至少指向文件的情况下测量性能。在任何类型的控制台上显示通常都是非常昂贵的IO,并且总是会扭曲时间——即使不是如此令人困惑。
- @博克恩斯:当然,这仍然会产生一个适当的问题。问题仍然是打印BS需要更长的时间,而不打印它们并不是真正的解决方案,而是帮助调试问题的一个技巧。
- 这仍然是猜测吗?我的意思是,system.out.print真的会自动换行吗?我们有文件吗?你能打开和关闭这个功能吗?
- @mrlister这不是System.out的问题,而是它的使用者的问题,在本例中是NetBeans的控制台视图。无论您是否可以关闭它,请检查NetBeans的设置。
- @李斯特:System.out.println不做换行,它输出的是换行(和阻塞,所以System.out.println必须等待)。
- @克里斯——事实上,我认为不打印是解决算法精确计时问题的方法。每次打印到控制台(任何类型)时,都会调用与测试性能无关的所有外部处理方式。这是你测量过程中的一个错误,简单明了。另一方面,如果您不把问题看作是测量,而是理解差异,那么是的,不打印是一个调试技巧。归根结底,你想解决哪个问题?
- @博克恩斯感谢你给这根线注入了理智!这么多人似乎不明白这一点。你要小心,你只是在测量你想测量的东西。
- @Sillyfreak你能告诉我"在B的情况下必须进行文字包装"是什么意思吗?
- @Koraytugay你从哪里得到报价?很明显,文字包装已经完成了,这就是问题所在,如果你想这样看的话。解决与这个问题有关的任何问题都不是"必须做的"。
- IO非常昂贵。我们曾经需要写入一个数据库随机数据。最初编写代码的人将printf("%s
",linecount);用于所有迭代。100万条参赛作品在24小时内未完成。我只需输入一个if(linecount%1000==)就可以在30秒内完成。
- Eclipse、NetBeans、Less、Gedit和Emacs都存在长线路的主要性能问题。不知怎的,他们设法写了一些代码,在行的长度上运行类似于O(n^2)。这是一个常见的、愚蠢的问题,在所有这些程序中都需要解决。
- 许多年前我注意到,当最小化时,应用程序在控制台上打印很多东西可以更快地运行,所以我认为输出流是一个阻塞操作,但从来没有想到流的另一端(在本例中是shell)将很难继续从流中取出东西。好球,好球。我想知道这些终端是否应该添加多线程以减少阻塞流的时间。
- @cleberz有很多我从命令运行的进程,我总是在最小化或很小的窗口中运行,因为它们以这种方式完成得非常快。
我在Eclipse和NETBease80.2上进行了测试,均使用Java版本1.8;我用System.nanoTime()作测量。
日食:
我在两个案例中都得到了相同的时间——大约1.564秒。
NETBES:
- 使用"":1.536秒
- 使用"B":44.164秒
所以,看起来NetBeans在打印到控制台上的性能很差。
经过更多的研究,我意识到问题在于netbeans的max buffer的行包装(不限于System.out.println命令),通过以下代码演示:
1 2 3 4 5 6 7
| for (int i = 0; i < 1000; i ++) {
long t1 = System. nanoTime();
System. out. print("BBB......BBB"); \\ <-contain 1000"B"
long t2 = System. nanoTime();
System. out. println(t2 -t1 );
System. out. println("");
} |
每次迭代的时间结果小于1毫秒,除了第五次迭代,时间结果大约为225毫秒。比如(以纳秒计):
1 2 3 4 5 6 7 8 9 10 11 12 13
| BBB...31744
BBB...31744
BBB...31744
BBB...31744
BBB...226365807
BBB...31744
BBB...31744
BBB...31744
BBB...31744
BBB...226365807
.
.
. |
等等…
总结:
Eclipse与"B"完美结合
NetBeans有一个可以解决的行包装问题(因为问题不会出现在Eclipse中)(在b("b")之后不添加空格)。
- 你能详细阐述一下你的研究策略吗?最后是什么让你发现包装线是罪魁祸首?(我对你的侦查技巧很好奇,就是这样!)