Dalam kode ini ketika saya membuat Objek dalam main
metode dan kemudian memanggil metode objek: ff.twentyDivCount(i)
(berjalan dalam 16010 ms), itu berjalan jauh lebih cepat daripada memanggilnya menggunakan anotasi ini: twentyDivCount(i)
(berjalan dalam 59516 ms). Tentu saja, ketika saya menjalankannya tanpa membuat objek, saya membuat metode ini statis, sehingga bisa dipanggil di main.
public class ProblemFive {
// Counts the number of numbers that the entry is evenly divisible by, as max is 20
int twentyDivCount(int a) { // Change to static int.... when using it directly
int count = 0;
for (int i = 1; i<21; i++) {
if (a % i == 0) {
count++;
}
}
return count;
}
public static void main(String[] args) {
long startT = System.currentTimeMillis();;
int start = 500000000;
int result = start;
ProblemFive ff = new ProblemFive();
for (int i = start; i > 0; i--) {
int temp = ff.twentyDivCount(i); // Faster way
// twentyDivCount(i) - slower
if (temp == 20) {
result = i;
System.out.println(result);
}
}
System.out.println(result);
long end = System.currentTimeMillis();;
System.out.println((end - startT) + " ms");
}
}
EDIT: Sejauh ini tampaknya mesin yang berbeda menghasilkan hasil yang berbeda, tetapi menggunakan JRE 1.8. * Adalah saat hasil aslinya tampak direproduksi secara konsisten.
+PrintCompilation +PrintInlining
ditunjukkanJawaban:
Menggunakan JRE 1.8.0_45 saya mendapatkan hasil yang serupa.
Penyelidikan:
-XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation -XX:+PrintInlining
opsi VM menunjukkan bahwa kedua metode dikompilasi dan disisipkanmain
sangat berbeda, dengan metode instans dioptimalkan secara lebih agresif, terutama dalam hal membuka gulungan loopSaya kemudian menjalankan pengujian Anda lagi tetapi dengan pengaturan loop unrolling yang berbeda untuk mengkonfirmasi kecurigaan di atas. Saya menjalankan kode Anda dengan:
-XX:LoopUnrollLimit=0
dan kedua metode berjalan lambat (mirip dengan metode statis dengan opsi default).-XX:LoopUnrollLimit=100
dan kedua metode berjalan cepat (mirip dengan metode instance dengan opsi default).Sebagai kesimpulan tampaknya, dengan pengaturan default, JIT dari hotspot 1.8.0_45 tidak dapat membuka gulungan ketika metode statis (meskipun saya tidak yakin mengapa berperilaku seperti itu). JVM lain mungkin memberikan hasil yang berbeda.
sumber
Hanya tebakan yang belum terbukti berdasarkan jawaban assylias.
JVM menggunakan ambang untuk membuka gulungan loop, yang kira-kira 70. Untuk alasan apa pun, panggilan statis sedikit lebih besar dan tidak dapat dibuka.
Perbarui hasil
LoopUnrollLimit
di bawah 52, kedua versi lambat.Ini aneh karena dugaan saya adalah bahwa panggilan statis hanya sedikit lebih besar di representasi internal dan OP mengalami kasus yang aneh. Tetapi perbedaannya tampaknya sekitar 20, yang tidak masuk akal.
-XX:LoopUnrollLimit=51 5400 ms NON_STATIC 5310 ms STATIC -XX:LoopUnrollLimit=52 1456 ms NON_STATIC 5305 ms STATIC -XX:LoopUnrollLimit=71 1459 ms NON_STATIC 5309 ms STATIC -XX:LoopUnrollLimit=72 1457 ms NON_STATIC 1488 ms STATIC
Bagi yang mau bereksperimen, versi saya semoga bermanfaat.
sumber
NON_STATIC
danSTATIC
, tapi kesimpulan saya benar. Diperbaiki sekarang, terima kasih.Ketika ini dijalankan dalam mode debug, jumlahnya sama untuk instance dan kasus statis. Itu lebih lanjut berarti bahwa JIT ragu-ragu untuk mengkompilasi kode ke kode asli dalam kasus statis dengan cara yang sama seperti yang dilakukannya dalam kasus metode instance.
Mengapa demikian? Sulit untuk mengatakannya; mungkin itu akan melakukan hal yang benar jika ini adalah aplikasi yang lebih besar ...
sumber
Saya hanya mengubah tes sedikit dan saya mendapatkan hasil sebagai berikut:
Keluaran:
Dynamic Test: 465585120 232792560 232792560 51350 ms Static Test: 465585120 232792560 232792560 52062 ms
CATATAN
Saat saya mengujinya secara terpisah, saya mendapat ~ 52 detik untuk dinamis dan ~ 200 detik untuk statis.
Ini programnya:
public class ProblemFive { // Counts the number of numbers that the entry is evenly divisible by, as max is 20 int twentyDivCount(int a) { // Change to static int.... when using it directly int count = 0; for (int i = 1; i<21; i++) { if (a % i == 0) { count++; } } return count; } static int twentyDivCount2(int a) { int count = 0; for (int i = 1; i<21; i++) { if (a % i == 0) { count++; } } return count; } public static void main(String[] args) { System.out.println("Dynamic Test: " ); dynamicTest(); System.out.println("Static Test: " ); staticTest(); } private static void staticTest() { long startT = System.currentTimeMillis();; int start = 500000000; int result = start; for (int i = start; i > 0; i--) { int temp = twentyDivCount2(i); if (temp == 20) { result = i; System.out.println(result); } } System.out.println(result); long end = System.currentTimeMillis();; System.out.println((end - startT) + " ms"); } private static void dynamicTest() { long startT = System.currentTimeMillis();; int start = 500000000; int result = start; ProblemFive ff = new ProblemFive(); for (int i = start; i > 0; i--) { int temp = ff.twentyDivCount(i); // Faster way if (temp == 20) { result = i; System.out.println(result); } } System.out.println(result); long end = System.currentTimeMillis();; System.out.println((end - startT) + " ms"); } }
Saya juga mengubah urutan tes menjadi:
public static void main(String[] args) { System.out.println("Static Test: " ); staticTest(); System.out.println("Dynamic Test: " ); dynamicTest(); }
Dan saya mendapatkan ini:
Static Test: 465585120 232792560 232792560 188945 ms Dynamic Test: 465585120 232792560 232792560 50106 ms
Seperti yang Anda lihat, jika dinamika dipanggil sebelum statis, kecepatan statis menurun secara dramatis.
Berdasarkan tolok ukur ini:
ATURAN DEMAM:
Java: kapan harus menggunakan metode statis
sumber
Silakan coba:
public class ProblemFive { public static ProblemFive PROBLEM_FIVE = new ProblemFive(); public static void main(String[] args) { long startT = System.currentTimeMillis(); int start = 500000000; int result = start; for (int i = start; i > 0; i--) { int temp = PROBLEM_FIVE.twentyDivCount(i); // faster way // twentyDivCount(i) - slower if (temp == 20) { result = i; System.out.println(result); System.out.println((System.currentTimeMillis() - startT) + " ms"); } } System.out.println(result); long end = System.currentTimeMillis(); System.out.println((end - startT) + " ms"); } int twentyDivCount(int a) { // change to static int.... when using it directly int count = 0; for (int i = 1; i < 21; i++) { if (a % i == 0) { count++; } } return count; } }
sumber