【问题标题】:Java OutputStream printing speedJava OutputStream 打印速度
【发布时间】:2020-10-09 19:29:03
【问题描述】:

假设我必须打印一个带有逗号分隔值的数组 arr。现在,我正在做以下事情:

for(int i = 0;i<arr.length;i++) {
    System.out.print(arr[i] + ",");
}

但是,对于较大的 arr 长度,我想知道这是否真的很慢。我想到的第二种方法是使用 StringBuilder,构造最终的输出字符串,并且只使用 1 个打印语句。那值得去吗?权衡将是更复杂的代码。

如果重要的话,我想要一个打印到控制台和打印到文件的答案。

【问题讨论】:

  • System.out.print(String.join(", ", arr))?您是否确定这是需要优化的重要应用程序瓶颈?
  • (1-) 但是,对于较大的 arr 长度,我想知道这是否真的很慢。 - 试试看。 我想到的第二种方法是使用 StringBuilder, - 现在需要权衡,因为在内存中有两个数据副本。如果您决定使用这种方法,请使用StringJoiner
  • 除非您要打印数万行,否则我认为您不会注意到任何速度差异。除非您注意到速度问题,否则何必费心优化?
  • 现在,您生成的 CSV 有点不正确:最后一个值后面有一个逗号。我的观点是:首先让您的代码正确且可读。然后运行它。当你说“哦,这太慢了”时,就要担心性能了。
  • 是的:这不是最优的:打印到标准输出的成本大约为毫秒,而在内存中连接字符串运行得更快。因此,如果您有 100 万个值,打印一百万个字符串或打印一个非常大的字符串之间可能会有明显的差异。

标签: java stringbuilder outputstream


【解决方案1】:

此代码效率不高,因为每次计算arr[i] + "," 时都必须实例化一个新字符串,这需要分配一个新的内存槽并在完成后用垃圾收集器丢弃旧字符串。

Dave Newton 给出的解决方案是打印阵列的最有效方法。我用一个包含 20 000 个元素的数组做了一个小基准测试(我可以在我的小型 PC 中选择的最大数字,因为当数组太大时显示数组往往会扭曲计算时间):

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        String[] array = new String[20000];
        Arrays.fill(array, "A");

        long t0 = System.currentTimeMillis();

        /* Test 1 : using a for loop */
        for (int i = 0; i < array.length; i++)
            System.out.print(array[i] + ",");
    
        System.out.println();
        long t1 = System.currentTimeMillis();

        /* Test 2 : using a for-each loop */
        for (String a : array)
            System.out.print(a + ",");
    
        System.out.println();
        long t2 = System.currentTimeMillis();

        /* Test 3 : using String.join */
        System.out.println(String.join(",", array));
        long t3 = System.currentTimeMillis();
    
        System.out.println("Test 1 : " + (t1 - t0) + "ms");
        System.out.println("Test 2 : " + (t2 - t1) + "ms");
        System.out.println("Test 3 : " + (t3 - t2) + "ms");
    }
}

我有以下结果:

Test 1 : 110ms
Test 2 : 93ms
Test 3 : 0ms

This website 解释了原因。 String.join 生成一个 StringJoiner 实例,该实例将字符存储在 StringBuilder 中。

StringBuilder 用作缓冲区;在缓冲区中附加Strings 然后显示结果比多次实例化 2 Strings 的总和更有效。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-23
    • 1970-01-01
    • 2018-03-13
    • 1970-01-01
    • 2016-10-10
    • 2016-10-14
    • 2014-11-01
    • 1970-01-01
    相关资源
    最近更新 更多