Java-программа замедляется при перенаправлении стандартного вывода в файл - PullRequest
0 голосов
/ 15 мая 2018

У меня есть простая автономная Java-программа, которая выводит некоторые данные на консоль с помощью System.out.println/printf.

Программе требуется около 3 секунды , чтобы прочитать ее ввод и записать вывод в консоль . Выходные данные содержат около 1000 строк по 200 символов в каждой, что в сумме составляет около 200 кБ.

Если я запускаю его с перенаправлением stdout в файл , то это займет в течение 2 минут для завершения.

ОС - RedHat Linux, оболочка - bash. Минимальный пример, который показывает тот же эффект:

public class WriteToStdout { // write ~100K to stdout
  public static void main( String[] args ) {
    for ( int i = 0; i < 100; i++ ) {
        System.out.printf( "%1000d\n", 1234 );
    }
}

Беги так:

/home/gsl> time java WriteToStdout
  ... console output omitted ...
real    0m0.163s
user    0m0.147s
sys     0m0.032s

/home/gsl> time java WriteToStdout > file

real    0m1.045s
user    0m0.151s
sys     0m0.036s

Диск, показанный ниже, работает быстро: если я копирую файлы или выполняю yes > file, он записывает около 100 МБ в секунду, как и ожидалось.

Если я перенаправлю через cat, то снова быстро :

/home/gsl> time java WriteToStdout | cat > file

real    0m0.152s
user    0m0.146s
sys     0m0.029s

Все одиночные тесты повторялись много раз и показывают одинаковое время при каждом запуске.

Так что же делает JVM, когда видит, что я перенаправляю в файл?

1 Ответ

0 голосов
/ 15 мая 2018

Попробуйте добавить некоторую буферизацию, примерно так:

public class WriteToStdout
{

  // write ~100K to stdout
  public static void main( String[] args )
  {
    final PrintStream myout = new PrintStream( new BufferedOutputStream( System.out ) );
    for ( int i = 0; i < 100; i++ )
    {
        myout.printf( "%1000d\n", 1234 );
    }
  }

}

Редактировать

По умолчанию PrintStream не выполняет буферизацию, поэтому каждая операция write выполняется непосредственно в потоке, который ее поддерживает. printf с другой стороны печатает каждую маску и тексты между ними отдельно.

Это означает, что printf( '%d\n', 1 ) записывается как две разные записи, каждая записывает один байт ...

Что касается вашего вопроса:
Перенаправление через канал (|) выполняется в памяти, поэтому запись на диск не выполняется ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...