印刷成本的“经验法则”

8
我注意到

在IT技术方面,

int i=10000000;
boolean isPrime= false;
      while(!isPrime){
           i++;
           System.out.println(item); //this kills performance
           isPrime = checkIfPrime(i);

     }
}

打印当前变量的值会降低性能。我想偶尔打印一下,但要保持其操作的成本低。

如何比较屏幕打印和计算的成本?有什么技巧可以最小化此成本[我应该每10个记录打印一个,还是由于条件检查,这将花费同样多的成本]?


为什么我需要这个?呃,我正在使用Java进行有趣的事情(例如,“找到Euler猜想的反例...27 ^ 5 + 84 ^ 5 + 110 ^ 5 + 133 ^ 5 = 144 ^ 5(Lander& Parkin,1966)”。) 我想编写既正确又快速的程序(这个反例是在60秒内发现的,所以我应该能够在合理的时间内完成它)。在调试时,我希望尽可能获得更多信息,并尽快找到反例。我的最佳方法是什么?打印每个案例吗?-太慢了。让它在过夜?如果我错过了一些 i ++怎么办?


你的成本在于将数据推送到终端(UI层),这会减慢速度,也就是瓶颈所在。 - Tim
是的。我的问题是 - 提供一些数据但不要减慢速度的技巧是什么?我想要一些输出,但我不想显著减慢速度。说“如果这是第100次尝试,请打印”与“每次都打印”的成本会是多少? - sixtytrees
我在我的回答中写了计算示例。如果您喜欢我的回答,可以接受,否则请让我知道是否需要更多解释。 - Tejus Prasad
7个回答

7
如何比较屏幕打印和计算的成本? 这是不可能的。打印的成本(即经过的时间)取决于“打印”字符的位置。我可以轻松构造一个例子,其中成本趋近于无穷大。
  $ java YourClass | ( sleep 10000000000 )

在输出几行后,管道缓冲区将会填满,应用程序中的print调用将会阻塞。

有没有什么技巧可以最小化这个代价[我应该每10条记录打印一次,还是由于条件检查而造成同样的代价]?

没有任何东西不会引入其他开销;例如测试是否要打印的开销。

完全消除打印开销的唯一方法就是在尝试测量性能时不打印


我的最佳方式是什么?每种情况都打印吗?- 太慢了。让它在夜间运行?如果我错过了某些i ++怎么办?

首先使用打印语句运行程序以检查您是否获得了正确的答案。

然后删除打印语句并再次运行以获取性能度量。

然而:

  1. 要注意编写Java微基准测试中的各种陷阱。
  2. 浏览页数众多的跟踪打印不是检查(可能)程序错误的好方法。

假设我没有犯这种错误,"测试条件(可被1000整除)"与"每次打印"的成本比是多少?有没有一种简洁的方法以低成本打印每个第n个结果(比"如果此数字可被n整除,则打印"更好)? - sixtytrees
1
  1. 这是 (C(test) + 0.001 * C(print)) / C(print)。显然,C(print) 必须针对处理打印字符的特定方式进行测量。
  2. 不。
- Stephen C
1
「假设我没有犯这种错误。」- 我说的并不是指一个错误,只是举例说明估算印刷成本是「不可能」有意义的。 - Stephen C
@sixtytrees Ctrl/s是另一个例子。成本变得无限。你所要求的原则上是不可能的。 - user207421

3

是的,打印输出很费资源。处理器在打印到终端/IDE的时间内可以执行数百万次操作。如果你正在使用Eclipse或终端,这将非常耗时。如果你正在使用终端,你需要使用>>>将其重定向到文件,或者使用nioio库将其写入文件中。只有在必要情况下才打印输出,否则如果性能是一个问题,我认为你不应该打印输出。


此外,无论如何使用'System.out'进行日志记录都是一个非常糟糕的想法。 - Lew Bloch
是的,我知道。但如果必须打印,这比打印到终端/IDE更好。我不确定他为什么要打印。 - Tejus Prasad
1
那是否意味着写入文件比System.out.print()更省资源?为什么会这样? - coderrick

2
如果您需要对代码性能进行基准测试,则不能使用打印语句。在少量迭代中,您需要打印语句以进行调试,并在确定代码正确运行后删除打印语句,然后测量代码时间。
否则,如果您希望始终在代码中使用打印语句,则由您决定可以接受多少延迟。例如,Xeon处理器可以为您提供28-35 Gflops/IOPS(每秒操作次数),这意味着处理器每秒可以执行35*10^9个增量操作(它可以每秒执行i++ 35*10^9次)。根据这个答案(https://dev59.com/yXrZa4cB1Zd3GeqP2nIN#20683422),System.out.println() 大约需要1毫秒。因此,如果您对每10^6 i++ 进行打印,则消耗的时间将增加一倍。

2

以下是计算下一个质数并在过程中打印所有测试过的数字的最快方法(前提是下一个质数不会导致int溢出):

int i = 10000000;
boolean isPrime = false;
while (!isPrime) {
    i++;
    // System.out.println(item); //this kills performance
    isPrime = checkIfPrime(i);
}
for (int j = 10000001; j <= i; j++) sysout(j);

1
如何比较打印到屏幕和计算的成本?通过测量:实现两种方法(每行打印,每x行打印)并查看哪种更快,并保持调整x以在频繁状态更新和吞吐量之间进行合理的权衡。需要注意的是,打印成本受到打印对象的强烈影响。流是否缓冲或每个数字是否刷新?它是写入内存、SSD、普通硬盘还是连接到慢速USB 1端口的驱动器?这可以将写入性能更改1000倍,这就是为什么您应该测量特定用例的原因。

1
一种方法是:
在一个线程中执行任务,将想要输出的内容更新到一个公共缓冲区(字符串?信息类的实例?),但不要在该线程中执行实际输出。请注意锁定该缓冲区,以便您可以安全地从不同的线程访问此信息。
然后,让定时器/其他线程访问这个公共缓冲区以打印出该信息。这样,您就可以将计算与输出分离开来。缺点是您将无法看到每个输出,但在生成输出时,计算仍在继续。

1

简短回答是:这真的取决于情况。打印文本很昂贵。一百次"print i"比使用stringbuilder构建字符串并一次性打印更加昂贵。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接