У напрузі є дві "сили": Продуктивність проти читабельності.
Давайте спочатку розглянемо третю проблему довгими рядками:
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-константа відбуватиметься під час компіляції і не матиме ніякого впливу на продуктивність. Рядки читаються, і ви можете просто рухатися далі.
Тепер про:
System.out.println("Good morning.");
System.out.println("Please enter your name");
vs.
System.out.println("Good morning.\nPlease enter your name");
Другий варіант значно швидший. Я підкажу про 2X як швидко .... чому?
Оскільки 90% роботи (з широкою помилкою) роботи не пов'язане із скиданням символів на вихід, а є накладними, необхідними для забезпечення виводу для запису на нього.
Синхронізація
System.out
є PrintStream
. Усі реабілітації Java, які мені відомі, внутрішньо синхронізують PrintStream: Дивіться код на GrepCode! .
Що це означає для вашого коду?
Це означає, що кожного разу, коли ви телефонуєте, System.out.println(...)
ви синхронізуєте свою модель пам'яті, ви перевіряєте і чекаєте блокування. Будь-які інші потоки, що викликають System.out, також будуть заблоковані.
У однопотокових програмах вплив System.out.println()
часто обмежується продуктивністю введення-виводу вашої системи, як швидко ви можете записати файл. У багатопотокових програмах блокування може бути більшою проблемою, ніж IO.
Промивання
Кожен 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
Вихід (помилково) виглядає так:
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
Це набагато повільніше, але пропорції приблизно однакові….