为什么打印"B"比打印"#"要慢得多?

Kuba Spatny 2662 java performance loops for-loop system.out

我生成了两个1000x 矩阵1000:

第一矩阵: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.8871几秒钟,而System.out.print("B");给出still printing....

正如其他人指出它通常适用于他们一样,我尝试过Ideone.com,两段代码都以相同的速度执行.

测试条件:

  • 我从Netbeans 7.2运行了这个测试,输出到它的控制台
  • 我用于System.nanoTime()测量

T.J. Crowder.. 3994

纯粹的推测是你正在使用一个试图进行自动换行而不是字符换行的终端,并将其视为B一个单词字符,而不是#一个非单词字符.因此,当它到达一条线的末端并寻找一条断线的地方时,它#几乎立刻就会看到并在那里快乐地打破; 而对于它B,它必须继续搜索更长的时间,并且可能有更多的文本要包装(在某些终端上可能很昂贵,例如,输出退格,然后输出空格来覆盖被包装的字母).

但那是纯粹的猜测.

  • 这实际上是正确的答案!在`B`之后添加一个空格来解决它. (540认同)
  • 精彩演绎.但是我们应该从本课中概括,并始终测量性能,输出要么被淘汰,要么导致/ dev/null(Windows上的NUL)或者至少是文件.在任何类型的控制台上显示通常都是非常昂贵的IO,并且总是会使时序失真 - 即使不像这样令人困惑. (306认同)
  • 有一些答案来自艰苦的学习经验.TJ和我(因为我们是朋友)在Apple [和zx80 /​​ 81]时代长大.那时没有内置的自动换行.所以我们最终都写了自己的 - 不止一次.那些课程坚持你,他们被焚烧到你的蜥蜴大脑.但是,如果您在此之后倾向于代码,当您的环境词包装所有内容,或者您​​在运行时之前手动执行它时,更难以遇到自动换行的问题. (254认同)
  • @MrLister:`System.out.println`不进行wordwrapping; 它输出的东西是自动换行(和阻塞,所以`System.out.println`必须等待). (35认同)
  • @Chris - 实际上,我认为不打印它们就是解决问题的方法,也就是获得算法精确计时的问题.每次打印到控制台(任何类型)时,您都会调用与您正在测试其性能无关的所有外部处理方式.这是您测量过程中的一个错误,纯粹而简单.另一方面,如果您将问题视为不是测量,而是了解差异,那么是的,不打印是一个调试技巧.归结为,你试图解决哪个问题? (34认同)
  • @BobKerns:当然,这仍然会产生一个合适的问题.问题仍然是打印Bs需要更长时间而不打印它们并不是解决方案,而是帮助调试问题的技巧. (17认同)
  • @BobKerns感谢您为这个帖子注入了一些理智!很多人似乎都不明白这一点.你需要小心,你只是在测量你想要测量的东西** (9认同)
  • @MrLister这不是System.out的问题,而是它的使用者,在这种情况下是NetBeans的控制台视图.您是否可以将其关闭,请检查Netbeans的设置. (7认同)
  • IO疯狂昂贵.我们曾经需要写一个DB随机数据.最初编写代码的人放了printf("%s\r \n",lineCount); 对于所有迭代.100万条目在24小时内没有完成.我只需输入一个if(lineCount%1000 ==)并在30秒内完成. (6认同)
  • 这还在猜测吗?我的意思是,System.out.print实际上是自动换行吗?我们在哪里有文件吗?你可以打开和关闭这个功能吗? (2认同)
  • 这是有史以来最伟大的SO答案之一 (2认同)

Roy Shmuli.. 194

我在Eclipse vs 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"); \\<-contain 1000 "B"
    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")之后没有添加空格).

  • 你能详细说明你的研究策略,然后最终导致你发现线条缠绕是罪魁祸首吗?(我很好奇你的侦探技巧,就是这样!) (30认同)