为什么打印“B”比打印“#”慢得多?

Why is printing "B" dramatically slower than printing "#"?

提问人:Kuba Spatny 提问时间:2/22/2014 最后编辑:Dmitriy PopovKuba Spatny 更新时间:7/5/2023 访问量:256657

问:

我生成了两个 x 矩阵:10001000

第一个矩阵:和 .
第二个矩阵:和 .
O#OB

使用以下代码,第一个矩阵需要 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("");
}

运行时间截然不同的原因是什么?


正如评论中建议的那样,打印只需几秒钟,而给出 .System.out.print("#");7.8871System.out.print("B");still printing...

正如其他人指出的那样,它通常对他们有效,例如,我尝试了 Ideone.com,并且两段代码以相同的速度执行。

测试条件:

  • 我从 Netbeans 7.2 运行了此测试,并将输出到其控制台中
  • 我用于测量System.nanoTime()
Java 性能 循环 for-loop system.out

评论

66赞 fejese 2/22/2014
尝试将 rand.nextInt(4) == 0 更改为 i < 250 以消除随机生成器的影响。您可能会耗尽熵,从而减慢随机生成的速度
3赞 Sotirios Delimanolis 2/22/2014
两者似乎在我的机器上运行相同的时间,~4 秒。
172赞 Kakarot 2/22/2014
如果您建议打印 B 比打印 #....你为什么不尝试打印所有 B 和 all #,而不是依赖随机变量 r
21赞 Barmar 2/23/2014
根据接受的答案,您显然没有尝试在输出重定向到文件或 /dev/null 的情况下运行它。
29赞 Divide 2/25/2014
@fejese,Random() 不是加密 rng,因此不会耗尽熵池。

答:

4250赞 9 revs, 7 users 35%T.J. Crowder #1

纯粹的推测是,您正在使用一个终端,该终端尝试进行自动换行而不是字符换行,并被视为单词字符但被视为非单词字符。因此,当它到达一条线的尽头并寻找一个突破线的地方时,它几乎立即看到一条线并愉快地在那里断线;而使用 ,它必须继续搜索更长的时间,并且可能有更多的文本要换行(这在某些终端上可能很昂贵,例如,输出退格,然后输出空格以覆盖正在换行的字母)。B##B

但这纯粹是猜测。

评论

357赞 Bob Kerns 2/24/2014
精彩的演绎。但是,我们应该从本课中总结出来,并始终使用消除输出、指向 /dev/null(在 Windows 上为 NULL)或至少指向文件来衡量性能。在任何类型的控制台上显示通常都是非常昂贵的 IO,并且总是会扭曲计时 - 即使没有像这样令人困惑。
20赞 Chris 2/24/2014
@BobKerns:当然,这仍然会产生一个适当的问题。问题仍然存在,打印 B 需要更长的时间,而不打印它们并不是真正的解决方案,而是帮助调试问题的技巧。
44赞 T.J. Crowder 2/27/2014
@MrLister:不做自动换行;它输出的东西是做自动换行(和阻塞,所以不得不等待)。System.out.printlnSystem.out.println
47赞 Bob Kerns 3/3/2014
@Chris -- 实际上,我认为不打印它们是解决方案,可以解决算法的准确计时问题。每次打印到控制台(任何类型的)时,您都会调用与测试性能无关的各种外部处理。这是测量过程中的一个错误,纯粹而简单。另一方面,如果您不将问题视为测量,而是理解差异,那么是的,不打印是一种调试技巧。归根结底,你想解决哪个问题?
15赞 UpAndAdam 4/5/2014
@BobKerns 感谢您为这个线程注入一些理智!很多人似乎不明白这一点。你需要小心,你只测量你试图测量的东西
257赞 Roy Shmuli 4/3/2015 #2

我在 Eclipse 和 Netbeans 8.0.2 上进行了测试,两者都使用 Java 版本 1.8; 我用来测量。System.nanoTime()

日蚀:

我在两种情况下都得到了相同的时间——大约 1.564 秒

Netbeans:

  • 使用“#”:1.536 秒
  • 使用“B”:44.164 秒

因此,看起来 Netbeans 在打印到控制台时性能不佳。

经过更多的研究,我意识到问题在于 Netbeans 的最大缓冲区的换行(它不限于命令),由以下代码演示:System.out.println

    for (int i = 0; i < 1000; i++) {
        long t1 = System.nanoTime();
        System.out.print("BBB......BBB"); // <- contains 1000 "B"s
        long t2 = System.nanoTime();
        System.out.println(t2 - t1);
        System.out.println("");
    }

时间结果每次迭代小于 1 毫秒,但每五次迭代除外,当时间结果约为 225 毫秒时。类似于(以纳秒为单位):

BBB...31744
BBB...31744
BBB...31744
BBB...31744
BBB...226365807
BBB...31744
BBB...31744
BBB...31744
BBB...31744
BBB...226365807
.
.
.

等等。

总结:

  1. Eclipse 与“B”完美配合
  2. Netbeans 有一个可以解决的换行问题(因为该问题不会在 eclipse 中发生)(无需在 B (“B”) 后面添加空格)。

评论

42赞 silph 10/30/2016
您能否详细说明一下您的研究策略,然后是什么最终导致您发现换行是罪魁祸首?(我很好奇你的侦探技巧,就是这样!
1赞 Thorbjørn Ravn Andersen 7/4/2020
可以禁用 Netbeans 中的自动换行。
2赞 scottb 3/19/2021
“我使用了 System.nanoTime()” ...一般来说,没有专门构建的基准测试工具的微基准测试是没有意义的。
21赞 Abdul Alim Shakir 9/5/2019 #3

是的,罪魁祸首绝对是换行。当我测试您的两个程序时,NetBeans IDE 8.2 给了我以下结果。

  1. 第一个矩阵:O 和 # = 6.03 秒
  2. 第二个矩阵:O 和 B = 50.97 秒

仔细查看您的代码:您在第一个循环的末尾使用了换行符。但是您在第二个循环中没有使用任何换行符。因此,您将在第二个循环中打印一个包含 1000 个字符的单词。这会导致自动换行问题。如果我们在 B 后面使用非单词字符 “ ”,编译程序只需要 5.35 秒。如果我们在传递 100 个值或 50 个值后在第二个循环中使用换行符,则分别只需要 8.56 秒7.05 秒

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");
        }

        if (j % 100 == 0) { // Adding a line break in second loop      
            System.out.println();
        }                    
    }

    System.out.println("");                
}

另一个建议是更改 NetBeans IDE 的设置。首先,转到 NetBeans Tools,然后单击 “Options”(选项)。之后,单击“编辑器”,然后转到“格式”选项卡。然后选择“换行选项中的任意位置”。编译程序所需的时间将减少近 6.24%。

NetBeans Editor Settings

评论

4赞 eis 1/18/2021
“编译程序所需的时间将减少近 6.24%。” 当然,您指的是执行,而不是编译......