Здесь есть две «силы» в напряжении: производительность против читабельности.
Давайте сначала рассмотрим третью проблему - длинные строки:
System.out.println("Good morning everyone. I am here today to present you with a very, very lengthy sentence in order to prove a point about how it looks strange amongst other code.");
Лучший способ реализовать это и сохранить читабельность - использовать конкатенацию строк:
System.out.println("Good morning everyone. I am here today to present you "
+ "with a very, very lengthy sentence in order to prove a "
+ "point about how it looks strange amongst other code.");
Конкатенация String-constant происходит во время компиляции и никак не влияет на производительность. Строки читабельны, и вы можете просто двигаться дальше.
Теперь о:
System.out.println("Good morning.");
System.out.println("Please enter your name");
против
System.out.println("Good morning.\nPlease enter your name");
Второй вариант значительно быстрее. Я посоветую примерно в 2 раза быстрее .... почему?
Потому что 90% (с большим пределом погрешности) работы не связаны с выгрузкой символов в вывод, а являются накладными расходами, необходимыми для защиты вывода для записи в него.
синхронизация
System.out
является PrintStream
. Все известные мне Java-реализации внутренне синхронизируют PrintStream: см. Код на GrepCode! ,
Что это значит для вашего кода?
Это означает, что каждый раз, когда вы звоните, System.out.println(...)
вы синхронизируете модель памяти, вы проверяете и ожидаете блокировки. Любые другие потоки, вызывающие System.out, также будут заблокированы.
В однопоточных приложениях влияние System.out.println()
часто ограничивается производительностью ввода-вывода вашей системы, как быстро вы можете записывать в файл. В многопоточных приложениях блокировка может быть более серьезной проблемой, чем IO.
смывание
Каждый отпечаток сбрасывается . Это приводит к очистке буферов и запускает запись на уровне консоли в буферы. Количество предпринимаемых здесь усилий зависит от реализации, но, как правило, следует понимать, что производительность сброса лишь в небольшой части связана с размером очищаемого буфера. Существуют значительные издержки, связанные с сбросом, когда буферы памяти помечаются как грязные, виртуальная машина выполняет ввод-вывод и так далее. Возложение этих накладных расходов один раз, а не дважды, является очевидной оптимизацией.
Некоторые цифры
Я собрал следующий маленький тест:
public class ConsolePerf {
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
benchmark("Warm " + i);
}
benchmark("real");
}
private static void benchmark(String string) {
benchString(string + "short", "This is a short String");
benchString(string + "long", "This is a long String with a number of newlines\n"
+ "in it, that should simulate\n"
+ "printing some long sentences and log\n"
+ "messages.");
}
private static final int REPS = 1000;
private static void benchString(String name, String value) {
long time = System.nanoTime();
for (int i = 0; i < REPS; i++) {
System.out.println(value);
}
double ms = (System.nanoTime() - time) / 1000000.0;
System.err.printf("%s run in%n %12.3fms%n %12.3f lines per ms%n %12.3f chars per ms%n",
name, ms, REPS/ms, REPS * (value.length() + 1) / ms);
}
}
Код относительно прост, он многократно печатает короткую или длинную строку для вывода. Длинная строка содержит несколько новых строк. Он измеряет, сколько времени требуется для печати 1000 итераций каждой.
Если я запускаю его в Unix (Linux) в командной строке, и перенаправить STDOUT
к /dev/null
, и распечатать фактические результаты STDERR
, я могу сделать следующее:
java -cp . ConsolePerf > /dev/null 2> ../errlog
Вывод (в errlog) выглядит так:
Warm 0short run in
7.264ms
137.667 lines per ms
3166.345 chars per ms
Warm 0long run in
1.661ms
602.051 lines per ms
74654.317 chars per ms
Warm 1short run in
1.615ms
619.327 lines per ms
14244.511 chars per ms
Warm 1long run in
2.524ms
396.238 lines per ms
49133.487 chars per ms
.......
Warm 99short run in
1.159ms
862.569 lines per ms
19839.079 chars per ms
Warm 99long run in
1.213ms
824.393 lines per ms
102224.706 chars per ms
realshort run in
1.204ms
830.520 lines per ms
19101.959 chars per ms
reallong run in
1.215ms
823.160 lines per ms
102071.811 chars per ms
Что это значит? Позвольте мне повторить последнюю строфу:
realshort run in
1.204ms
830.520 lines per ms
19101.959 chars per ms
reallong run in
1.215ms
823.160 lines per ms
102071.811 chars per ms
Это означает, что для всех намерений и целей, даже несмотря на то, что «длинная» строка примерно в 5 раз длиннее и содержит несколько новых строк, для вывода требуется примерно столько же времени, сколько для короткой строки.
Количество символов в секунду в долгосрочной перспективе в 5 раз больше, а истекшее время примерно одинаково .....
Другими словами, ваша производительность масштабируется относительно количества ваших отпечатков, а не того , что они печатают.
Обновление: что произойдет, если вы перенаправите в файл, а не в / dev / null?
realshort run in
2.592ms
385.815 lines per ms
8873.755 chars per ms
reallong run in
2.686ms
372.306 lines per ms
46165.955 chars per ms
Это намного медленнее, но пропорции примерно одинаковы ....