Самый быстрый способ для построчного чтения STDIN? - PullRequest
20 голосов
/ 25 января 2012

Я ищу наиболее эффективный по времени способ читать STDIN построчно.

Первая строка - количество условий для проверки. Все следующие строки - это условия (строки), содержащие не более 100 000 символов.

Я уже пробовал следующее (плюс результат для 4 раз 90 000 символов:

  • Сканер с временной петлей (7255 мс)

    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. 3228 мс для сканера, в то время как
      2. 2264 мс для сканера, в то время как
      3. 1309мс для сканера, в то время как
      4. 454 мс для сканера, в то время как
  • Сканер с циклом for (7078 мс)

    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. 3168мс для сканера для
      2. 2207мс для сканера для
      3. 1236мс для сканера для
      4. 467мс для сканера
  • BufferedReader с циклом for (7403 мс)

    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. 3273мс для буферного считывателя для
      2. 2330 мс для устройства чтения буфера для
      3. 1293мс для буферного считывателя для
      4. 507 мс для устройства чтения буфера для
  • BufferedReader с циклом while (7461 мс)

    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. 3296 мс для устройства чтения буфера, в то время как
      2. 2358 мс для устройства чтения буфера, а
      3. 1307 мс для устройства чтения буфера, в то время как
      4. 500 мс для устройства чтения буфера, а

Во время отладки затраченного времени я заметил, что затраченное время уменьшается после каждого чтения. Можно ли ограничить инициализируемые байты (например, если у вас есть максимум 100 000 символов, ограничьте сканер / буферизированный ридер только для инициализации 100 000 символов. После чтения необходимо будет пополнить себя следующими 100 000 символов)

Любые идеи по этому вопросу приветствуются.

РЕДАКТИРОВАТЬ: Добавлен код для каждого сценария, а также время чтения каждой строки. Также изменил 100 000 на 100 000, чтобы читать легче.

1 Ответ

5 голосов
/ 26 января 2012

Заглянул внутрь BufferedReader#readLine источника.Я вижу несколько проблем:

  1. Он использует StringBuffer вместо StringBuilder, что создает накладные расходы на синхронизацию.
  2. Также, похоже, накладные расходы на копирование данных - не совсем уверен, лучше проверитьit out.
  3. Выделенный объект монитора в BufferedReader и еще больше накладных расходов на синхронизацию.

Вы можете рискнуть двумя способами:

  1. Написание вашегособственная буферизация, которая может сэкономить некоторое время при двойном копировании данных.
  2. Написание собственного метода nextLine, который будет использовать StringBuilder и просматривать исходные данные простым циклом.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...