Ada dua 'kekuatan' di sini, dalam ketegangan: Kinerja vs Keterbacaan.
Mari kita atasi masalah ketiga terlebih dahulu, garis panjang:
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.");
Cara terbaik untuk menerapkan ini dan menjaga kewaspadaan, adalah dengan menggunakan penggabungan string:
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.");
Rangkaian string-konstan akan terjadi pada waktu kompilasi, dan tidak akan berpengaruh pada kinerja sama sekali. Garis-garisnya dapat dibaca, dan Anda bisa melanjutkan.
Sekarang, tentang:
System.out.println("Good morning.");
System.out.println("Please enter your name");
vs.
System.out.println("Good morning.\nPlease enter your name");
Opsi kedua secara signifikan lebih cepat. Saya akan menyarankan tentang 2X secepat .... mengapa?
Karena 90% (dengan margin kesalahan yang luas) dari pekerjaan tidak terkait dengan membuang karakter ke output, tetapi diperlukan overhead untuk mengamankan output untuk menulis padanya.
Sinkronisasi
System.out
adalah a PrintStream
. Semua implementasi Java yang saya ketahui, secara internal menyinkronkan PrintStream: Lihat kode di GrepCode! .
Apa artinya ini untuk kode Anda?
Ini berarti bahwa setiap kali Anda menelepon System.out.println(...)
Anda menyinkronkan model memori Anda, Anda sedang memeriksa dan menunggu kunci. Utas lain yang memanggil System.out juga akan dikunci.
Dalam aplikasi single-threaded dampaknya System.out.println()
sering dibatasi oleh kinerja IO sistem Anda, seberapa cepat Anda dapat menulis ke file. Dalam aplikasi multithreaded, penguncian bisa menjadi masalah daripada IO.
Pembilasan
Setiap println memerah . Ini menyebabkan buffer dibersihkan dan memicu penulisan tingkat Konsol ke buffer. Jumlah upaya yang dilakukan di sini tergantung pada implementasi, tetapi, secara umum dipahami bahwa kinerja flush hanya sebagian kecil terkait dengan ukuran buffer yang disiram. Ada overhead signifikan terkait dengan flush, di mana buffer memori ditandai sebagai kotor, mesin Virtual melakukan IO, dan sebagainya. Mengalami overhead itu sekali, bukan dua kali, merupakan pengoptimalan yang jelas.
Beberapa angka
Saya mengumpulkan tes kecil berikut:
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);
}
}
Kode ini relatif sederhana, berulang kali mencetak string pendek, atau panjang ke output. String panjang memiliki beberapa baris baru di dalamnya. Ini mengukur berapa lama untuk mencetak masing-masing 1.000 iterasi.
Jika saya menjalankannya di prompt perintah unix (Linux), dan mengarahkan ulang STDOUT
ke /dev/null
, dan mencetak hasil yang sebenarnya STDERR
, saya dapat melakukan hal berikut:
java -cp . ConsolePerf > /dev/null 2> ../errlog
Output (dalam errlog) terlihat seperti:
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
Apa artinya ini? Saya ulangi 'bait' terakhir:
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
Ini berarti bahwa, untuk semua maksud dan tujuan, meskipun garis 'panjang' sekitar 5 kali lebih lama, dan berisi beberapa baris baru, dibutuhkan output yang sama panjangnya dengan garis pendek.
Jumlah karakter per detik untuk jangka panjang adalah 5 kali lebih banyak, dan waktu yang berlalu hampir sama .....
Dengan kata lain, kinerja Anda berskala relatif terhadap jumlah cetak yang Anda miliki, bukan apa yang mereka cetak.
Pembaruan: Apa yang terjadi jika Anda mengarahkan ulang ke file, alih-alih ke / 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
Ini jauh lebih lambat, tetapi proporsinya hampir sama ....