逐行读取 STDIN 的最快方法?

2022-09-02 10:57:26

我正在寻找最省时的方式来逐行阅读STDIN。

第一行是要测试的条件数。以下所有行都是条件(字符串),最多包含 100 000 个字符。

我已经尝试了以下内容(加上4乘以90 000个字符的结果):

  • 带 while-loop 的扫描器 (7255 ms)

    Scanner sc = new Scanner(System.in);
    int numberOfLines = Integer.parseInt(sc.nextLine());
    long start = 0;
    int i = 1;
    while (i<=numberOfLines){
        start = System.currentTimeMillis();
        sc.nextLine();
        Debug.println((System.currentTimeMillis()-start) + "ms for scanner while");
        i++;
    }
    
    • 结果:
      1. 3228ms 用于扫描仪,同时
      2. 2264ms 用于扫描仪,同时
      3. 1309ms 用于扫描仪,同时
      4. 454ms 用于扫描仪,同时
  • 带 for-loop 的扫描器 (7078 ms)

    Scanner sc = new Scanner(System.in);
    int numberOfLines = Integer.parseInt(sc.nextLine());
    long start = 0;
    for (int i = 1; i<= numberOfLines;i++){
        start = System.currentTimeMillis();
        sc.nextLine();
        Debug.println((System.currentTimeMillis()-start) + "ms for scanner for");
        //i++;     
    }
    
    • 结果:
      1. 3168ms 用于扫描仪
      2. 2207ms 用于扫描仪
      3. 1236ms 用于扫描仪
      4. 467ms 用于扫描仪
  • 带 for 循环的缓冲读取器 (7403 ms)

    try {
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    
    int numberOfLines = Integer.parseInt(br.readLine());
    long start = 0;
    for (int i = 0; i< numberOfLines;i++){
        start = System.currentTimeMillis();
        br.readLine();
        Debug.println((System.currentTimeMillis()-start) + "ms for bufferreader for");
        //i++;
    }
     } catch (Exception e) {
    System.err.println("Error:" + e.getMessage());
    

    }

    • 结果:
      1. 3273ms 用于缓冲读取器
      2. 2330ms 用于缓冲读取器
      3. 1293ms 用于缓冲读取器
      4. 507ms 用于缓冲读取器
  • 带 while-loop 的 BufferedReader (7461 ms)

    try {
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    
    int numberOfLines = Integer.parseInt(br.readLine());
    int i=0;
    long start = 0;
    while(i< numberOfLines){
        start = System.currentTimeMillis();
        br.readLine();
        Debug.println((System.currentTimeMillis()-start) + "ms for bufferreader while");
        i++;
    }
     } catch (Exception e) {
    System.err.println("Error:" + e.getMessage());
    

    }

    • 结果:
      1. 3296ms 用于缓冲读取器,同时
      2. 缓冲读取器为 2358ms,同时
      3. 1307ms 用于缓冲读取器,同时
      4. 缓冲读取器为 500ms,同时

在调试所花费的时间时,我注意到每次读取后所花费的时间都会减少。是否可以限制初始化的字节(例如:如果最多有 100.000 个字符,请将扫描程序/缓冲读取器限制为仅初始化 100 000 个字符。读取后,它将需要用接下来的100 000个字符重新填充自己)

关于这个问题的任何想法都非常值得欢迎。

编辑:添加了每个场景的代码以及每行读取所花费的时间。还将100.000更改为100 000以更易于阅读。


答案 1

查看内部源。我看到了几个问题:BufferedReader#readLine

  1. 它使用 StringBuffer 而不是 StringBuilder,这会产生同步开销。
  2. 此外,似乎还有数据复制开销 - 不完全确定,最好检查一下。
  3. BufferedReader 中的专用监视器对象,甚至更多的同步开销。

您可能会在两件事上冒险:

  1. 编写自己的缓冲,这可以节省一些时间进行数据的双重复制。
  2. 编写您自己的 nextLine 方法,该方法将使用 StringBuilder 并通过简单的循环遍历源数据。

答案 2

推荐