Java - System.out对性能的影响

11

我看过这个问题,它有些相似。我想知道它是否真的是一个会影响我的应用程序性能的重要因素。以下是我的情况。

我有一个Java Web应用程序,可以从电子表格中上传成千上万条数据,每行从顶部到底部读取。我使用System.out.println()在服务器侧显示当前应用程序正在读取的行数。

- 我知道创建日志文件的方法。实际上,我正在创建一个日志文件,并同时在服务器提示窗口中显示日志。
还有其他打印当前数据到提示窗口的方法吗?


1
System.out是慢的,但它是否影响应用程序的整体性能完全取决于它所做的事情。这个问题不能直接回答。 - ewernli
你可以在另一个线程中打印输出。当然,这样你就无法准确了解代码的执行位置,但至少不会拖慢程序速度。请注意缓冲区的大小。 - jontejj
@ Michael Ardan:如果服务器处理了数千条记录并在控制台上打印出来,你真的能看到它们吗?这是用于调试吗? - Jayan
@Jayan:是的,可以从控制台看到。 - Michael 'Maik' Ardan
这也取决于您的代码执行中println调用与其他函数的比率。客观地说,它并不重要,但如果您的程序运行需要60秒,而过多的println占用了2秒钟,那么它似乎就不那么相关了。 - Cole Henrich
6个回答

15

最近我在测试读写大型文本文件(1-1.5GB),并发现:

PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(java.io.FileDescriptor.out), "UTF-8"), 512));
out.println(yourString);
//...
out.flush();

实际上比原来快250%

System.out.println(yourString);

我的测试程序首先读取了大约1GB的数据,稍微处理一下,然后以稍微不同的格式输出。

在MacBook Pro上进行的测试结果(使用SSD进行读写操作,同一块磁盘):

  • 将数据输出到系统输出 > 输出.txt => 1分32秒
  • 将数据写入Java文件中 => 37秒
  • 将数据写入缓冲区写入器标准输出 > 输出.txt => 36秒

我尝试了多个不同的缓冲区大小(在256-10k之间),但似乎并没有影响。

因此,请记住,如果您正在使用Java创建Unix命令行工具,并且输出需要被定向或者管道到其他地方,请不要直接使用System.out!


谢谢您提供的性能统计数据!使用 BufferedWriter 与使用 Logger 对象相比,在性能方面有何不同? - user3864935
现在这是一个缓冲写入器,当缓冲区满时性能如何比较? - tuskiomi
来自未来的问候!相比之下,2018年的GNU/Linux glibc stdout缓冲区为4096字节,而文件复制缓冲区为131072字节。复制工具“dd”由于规范而被困在默认的512字节缓冲区中(就像这个答案一样),这使得它在现代驱动器上受到CPU限制。 - that other guy

14

它可能会影响应用程序的性能。其影响的程度取决于您运行的硬件类型和主机负载。

下面是一些性能方面的要点:

-> 如Rocket boy所述,println是同步的,这意味着您将在对象标头上产生锁定开销,并且根据设计可能会导致线程瓶颈。

-> 在控制台上打印需要内核时间,内核时间意味着CPU不会在用户模式下运行,这基本上意味着您的CPU将忙于执行内核代码而不是应用程序代码。

-> 如果您已经记录了此内容,则意味着需要额外的内核时间进行I/O操作,如果您的平台不支持异步I/O,则这意味着您的CPU可能会在忙等待时停顿。

您可以尝试对此进行基准测试并自行验证。

有一些方法可以解决这个问题,例如具有非常快的I/O、专用使用的大型计算机以及JVM选项上的偏向锁定,如果您的应用程序设计不会在控制台上打印多线程。

像所有性能相关的事情一样,这取决于您的硬件和优先级。


如果我正在使用像Selenium的WebDriver这样的工具进行集成测试,那么在集成测试小型测试应用程序时,使用System.out.println会对性能产生多大影响? - user3864935

11
System.out.println()

已同步。

 public void println(String x) {
    synchronized (this) {
        print(x);
        newLine();
    }
如果有多个线程同时写入,它的性能将会受到影响。

4

是的,这将对性能产生巨大影响。如果你想要一个量化的数字,那么有很多软件和/或测量自己代码性能的方法。


3

与大多数缓慢的操作相比,System.out.println非常缓慢。这是因为它比其他IO操作更加繁重(并且是单线程的)。

我建议您将输出写入文件,并使用tail命令查看该文件的输出。这样,输出仍然很慢,但不会使您的Web服务变得太慢。


1

这是一个非常简单的程序,用于检查System.out.println的性能,并将其与乘法操作进行比较(您可以使用其他操作或特定于您要求的函数)。

public class Main{

 public static void main(String []args) throws InterruptedException{
             
    
    long tTime = System.nanoTime();
    long a = 123L;
    long b = 234L;
    
    long c  = a*b;
    long uTime = System.nanoTime();
    
    System.out.println("a * b = "+ c +". Time taken for multiplication =  "+ (uTime - tTime) + " nano Seconds");
    
    long vTime = System.nanoTime();
    System.out.println("Time taken to execute Print statement : "+ (vTime - uTime) + " nano Seconds");
    
 }
}

输出结果取决于您的计算机及其当前状态。

以下是我在https://www.onlinegdb.com/online_java_compiler上得到的结果。

a * b = 28782. Time taken for multiplication =  330 nano Seconds                                                                                                                     
Time taken to execute Print statement : 338650 nano Seconds 

编辑:

我在本地机器上设置了日志记录器,想要让你了解系统输出和日志记录器(即控制台打印与日志记录)之间的性能差异。

public static void main(String []args) throws InterruptedException{


        long tTime = System.nanoTime();
        long a = 123L;
        long b = 234L;

        long c  = a*b;
        long uTime = System.nanoTime();

        System.out.println("a * b = "+ c +". Time taken for multiplication =  "+ (uTime - tTime) + " nano Seconds");

        long vTime = System.nanoTime();
        System.out.println("Time taken to execute Print statement : "+ (vTime - uTime) + " nano Seconds");

        long wTime = System.nanoTime();
        logger.info("a * b = "+ c +". Time taken for multiplication =  "+ (uTime - tTime) + " nano Seconds");
        long xTime = System.nanoTime();
        System.out.println("Time taken to execute log statement : "+ (xTime - wTime) + " nano Seconds");

    }

这是我在本地机器上得到的内容:
a * b = 28782. Time taken for multiplication =  1667 nano Seconds
Time taken to execute Print statement : 34080917 nano Seconds
2022-11-15 11:36:32.734 [] INFO  CreditAcSvcImpl uuid:  - a * b = 28782. Time taken for multiplication =  1667 nano Seconds 
Time taken to execute log statement : 9645083 nano Seconds

请注意,system.out.println的执行时间比logger.info慢了将近24毫秒。

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