Mengapa mencetak "B" jauh lebih lambat daripada mencetak "#"?

2749

Saya menghasilkan dua matriks 1000x 1000:

Matriks Pertama: Odan #.
Matriks Kedua: Odan B.

Menggunakan kode berikut, matriks pertama membutuhkan 8,52 detik untuk selesai:

Random r = new Random();
for (int i = 0; i < 1000; i++) {
    for (int j = 0; j < 1000; j++) {
        if(r.nextInt(4) == 0) {
            System.out.print("O");
        } else {
            System.out.print("#");
        }
    }

   System.out.println("");
 }

Dengan kode ini, matriks kedua membutuhkan 259,152 detik untuk menyelesaikan:

Random r = new Random();
for (int i = 0; i < 1000; i++) {
    for (int j = 0; j < 1000; j++) {
        if(r.nextInt(4) == 0) {
            System.out.print("O");
        } else {
            System.out.print("B"); //only line changed
        }
    }

    System.out.println("");
}

Apa alasan di balik run time yang sangat berbeda?


Seperti yang disarankan dalam komentar, pencetakan hanya System.out.print("#");membutuhkan beberapa 7.8871detik, sedangkan System.out.print("B");memberi still printing....

Seperti orang lain yang menunjukkan bahwa itu bekerja untuk mereka secara normal, saya mencoba Ideone.com misalnya, dan kedua potongan kode dieksekusi pada kecepatan yang sama.

Kondisi pengujian:

  • Saya menjalankan tes ini dari Netbeans 7.2 , dengan output ke konsolnya
  • Saya digunakan System.nanoTime()untuk pengukuran
Kuba Spatny
sumber
62
Coba ubah rand.nextInt (4) == 0 ke i <250 untuk menghilangkan efek dari generator acak. Anda mungkin kehabisan entropi yang memperlambat generasi acak
fejese
3
Keduanya tampaknya berjalan untuk jumlah waktu yang sama di mesin saya, ~ 4 detik.
Sotirios Delimanolis
155
jika Anda menyarankan agar pencetakan B membutuhkan lebih banyak waktu daripada mencetak # .... mengapa Anda tidak mencoba mencetak semua B & semua # daripada mengandalkan variabel acak r
Kakarot
18
Berdasarkan jawaban yang diterima, Anda tampaknya tidak mencoba menjalankannya dengan output diarahkan ke file atau / dev / null.
Barmar
24
@fejese, Random () bukan rng kriptografis dan karenanya tidak menggunakan kumpulan entropi.
Bagilah

Jawaban:

4073

Spekulasi murni adalah bahwa Anda menggunakan terminal yang mencoba melakukan pembungkus kata daripada pembungkus karakter, dan memperlakukan Bsebagai karakter kata tetapi #sebagai karakter non-kata. Jadi ketika mencapai ujung garis dan mencari tempat untuk memecahkan garis, ia melihat #hampir segera dan dengan senang hati istirahat di sana; sedangkan dengan Bitu, ia harus terus mencari lebih lama, dan mungkin memiliki lebih banyak teks untuk dibungkus (yang mungkin mahal pada beberapa terminal, misalnya, menghasilkan backspaces, kemudian mengeluarkan spasi untuk menimpa huruf yang sedang dibungkus).

Tapi itu spekulasi murni.

TJ Crowder
sumber
560
Ini sebenarnya jawaban yang benar! Menambahkan spasi setelah Bmenyelesaikannya.
Kuba Spatny
261
Ada beberapa jawaban yang datang dari pengalaman yang sulit dipelajari. TJ dan saya (karena kami adalah teman) tumbuh pada zaman Apple] [dan zx80 / ​​81. Tidak ada built in word wrap saat itu. Jadi kami berdua akhirnya menulis sendiri - lebih dari sekali. Dan pelajaran-pelajaran itu tetap melekat pada Anda, mereka dibakar di otak kadal Anda. Tetapi jika Anda condong ke kode setelah itu, ketika kata lingkungan Anda membungkus semuanya, atau Anda melakukannya secara manual sebelum runtime, lebih sulit untuk mengalami masalah dengan bungkus kata.
JockM
315
Pengurangan brilian. Tetapi kita harus menggeneralisasi dari pelajaran ini, dan selalu mengukur kinerja dengan output baik dihilangkan, diarahkan ke / dev / null (NUL di Windows) atau setidaknya ke file. Menampilkan pada segala jenis Konsol pada umumnya IO sangat mahal, dan selalu mendistorsi timing - bahkan jika tidak sedramatis ini.
Bob Kerns
37
@ Mr.Lister: System.out.printlntidak melakukan wordwrapping; hal yang dikeluarkannya adalah melakukan pembungkusan kata (dan memblokir, jadi System.out.printlnharus menunggu).
TJ Crowder
35
@ Chris - sebenarnya, saya berpendapat bahwa tidak mencetaknya ADALAH solusinya, untuk masalah mendapatkan timing algoritma yang akurat. Setiap kali Anda mencetak ke Konsol (dalam bentuk apa pun), Anda memohon segala macam pemrosesan eksternal yang tidak terkait dengan apa yang Anda uji kinerja. Itu bug dalam prosedur pengukuran Anda, murni dan sederhana. Di sisi lain, jika Anda melihat masalah bukan sebagai pengukuran, tetapi memahami perbedaan, maka ya, tidak mencetak adalah trik debugging. Masalahnya adalah, masalah apa yang Anda coba selesaikan?
Bob Kerns
210

Saya melakukan tes pada Eclipse vs Netbeans 8.0.2, keduanya dengan Java versi 1.8; Saya digunakan System.nanoTime()untuk pengukuran.

Gerhana:

Saya mendapatkan waktu yang sama pada kedua kasus - sekitar 1,564 detik .

Netbeans:

  • Menggunakan "#": 1,536 detik
  • Menggunakan "B": 44,164 detik

Jadi, sepertinya Netbeans memiliki kinerja buruk di cetak ke konsol.

Setelah penelitian lebih lanjut saya menyadari bahwa masalahnya adalah pembungkus-line buffer maksimum Netbeans (tidak terbatas pada System.out.printlnperintah), ditunjukkan oleh kode ini:

for (int i = 0; i < 1000; i++) {
    long t1 = System.nanoTime();
    System.out.print("BBB......BBB"); \\<-contain 1000 "B"
    long t2 = System.nanoTime();
    System.out.println(t2-t1);
    System.out.println("");
}

Hasil waktu kurang dari 1 milidetik setiap iterasi kecuali setiap iterasi kelima , ketika hasil waktu sekitar 225 milidetik. Sesuatu seperti (dalam nanodetik):

BBB...31744
BBB...31744
BBB...31744
BBB...31744
BBB...226365807
BBB...31744
BBB...31744
BBB...31744
BBB...31744
BBB...226365807
.
.
.

Dan seterusnya..

Ringkasan:

  1. Eclipse bekerja sempurna dengan "B"
  2. Netbeans memiliki masalah pembungkus garis yang dapat diselesaikan (karena masalah tidak terjadi pada gerhana) (tanpa menambahkan spasi setelah B ("B")).
Roy Shmuli
sumber
32
dapatkah Anda menguraikan strategi penelitian Anda dan kemudian apa yang akhirnya membuat Anda mengetahui bahwa pembungkus garis adalah pelakunya? (Saya ingin tahu tentang keterampilan detektif Anda, itu!)
Silph
12

Ya pelakunya pasti pembungkus kata. Ketika saya menguji dua program Anda, NetBeans IDE 8.2 memberi saya hasil berikut.

  1. Matriks Pertama: O dan # = 6,03 detik
  2. Matriks Kedua: O dan B = 50,97 detik

Melihat kode Anda dari dekat, Anda telah menggunakan satu baris di akhir loop pertama. Tapi Anda tidak menggunakan garis apa pun di loop kedua. Jadi, Anda akan mencetak kata dengan 1000 karakter di loop kedua. Itu menyebabkan masalah pembungkusan kata. Jika kita menggunakan karakter non-kata "" setelah B, hanya butuh 5,35 detik untuk mengkompilasi program. Dan jika kita menggunakan garis putus-putus pada loop kedua setelah melewati 100 nilai atau 50 nilai, hanya dibutuhkan 8,56 detik dan 7,05 detik .

Random r = new Random();
for (int i = 0; i < 1000; i++) {
    for (int j = 0; j < 1000; j++) {
        if(r.nextInt(4) == 0) {
            System.out.print("O");
        } else {
            System.out.print("B");
        }
        if(j%100==0){               //Adding a line break in second loop      
            System.out.println();
        }                    
    }
    System.out.println("");                
}

Saran lain adalah mengubah pengaturan NetBeans IDE. Pertama-tama, buka NetBeans Tools dan klik Opsi . Setelah itu klik Editor dan pergi ke tab Format . Kemudian pilih Anywhere in Line Wrap Option. Butuh hampir 6,24% lebih sedikit waktu untuk menyusun program.

Pengaturan Editor NetBeans

Abdul Alim Shakir
sumber