ChatGPT解决这个技术问题 Extra ChatGPT

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

我生成了两个 1000 x 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() 进行测量

尝试将 rand.nextInt(4) == 0 更改为 i < 250 以消除随机生成器的影响。您可能会用完减慢随机生成的熵
两者似乎都在我的机器上运行了相同的时间,大约 4 秒。
如果您建议打印 B 比打印 #.... 为什么不尝试打印所有 B & all # 而不是依赖随机变量 r
根据接受的答案,您显然没有尝试将输出重定向到文件或 /dev/null 来运行它。
@fejese,Random() 不是加密 rng,因此不会用完熵池。

9
9 revs, 7 users 35%

纯猜测是您使用的终端尝试执行 word-wrapping 而不是字符换行,并将 B 视为单词字符,但将 # 视为非单词字符。因此,当它到达行尾并搜索断行的地方时,它几乎立即看到 # 并愉快地断行;而使用 B,它必须继续搜索更长的时间,并且可能有更多的文本要换行(这在某些终端上可能很昂贵,例如,输出退格,然后输出空格以覆盖被换行的字母)。

但这纯粹是猜测。


精彩演绎。但是我们应该从这节课中总结出来,并始终在输出被消除、定向到 /dev/null(Windows 上的 NUL)或至少到一个文件的情况下衡量性能。在任何类型的控制台上显示通常都是非常昂贵的 IO,并且总是会扭曲时间——即使没有像这样令人困惑。
@BobKerns:当然,这仍然会产生一个适当的问题。问题仍然是打印 Bs 需要更长的时间并且不打印它们并不是真正的解决方案,而是帮助调试问题的技巧。
@MrLister:System.out.println 不进行自动换行;它输出的东西是自动换行(和阻塞,所以 System.out.println 必须等待)。
@Chris——实际上,我认为不打印它们是解决获得算法准确时间问题的解决方案。每次打印到控制台(任何类型的)时,您都会调用与您正在测试的性能无关的各种外部处理方式。这是您的测量过程中的一个错误,纯粹而简单。另一方面,如果您不将问题视为测量,而是理解差异,那么是的,不打印是一种调试技巧。归根结底,您要解决哪个问题?
@BobKerns 感谢您为这个线程注入了一些理智!很多人似乎不明白这一点。你需要小心,你只是在测量你想要测量的东西
C
Community

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

蚀:

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

网豆:

使用“#”:1.536 秒

使用“B”:44.164 秒

因此,看起来 Netbeans 在打印到控制台方面的性能很差。

经过更多研究,我意识到问题出在 Netbeans 的最大缓冲区的 line-wrapping(它不限于 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
.
.
.

等等..

概括:

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


您能否详细说明您的研究策略,然后最终导致您发现换行是罪魁祸首? (我很好奇你的侦探技巧,就是!)
可以禁用 Netbeans 中的自动换行。
“我使用了 System.nanoTime()”……一般来说,没有专门构建的基准测试工具的微基准测试是没有意义的。
R
ROOT

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

第一个矩阵:O 和 # = 6.03 秒 第二个矩阵: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 工具并单击选项。之后单击编辑器并转到格式选项卡。然后选择换行选项中的任意位置。编译程序所需的时间将减少近 6.24%。

https://i.stack.imgur.com/yv2eL.jpg


“编译程序所需的时间将减少近 6.24%。”你肯定指的是执行,而不是编译......