Akurasi Vs. Presisi
Apa yang ingin saya ketahui adalah apakah saya harus menggunakan System.currentTimeMillis () atau System.nanoTime () ketika memperbarui posisi objek saya di game saya? Perubahan gerakan mereka berbanding lurus dengan waktu yang telah berlalu sejak panggilan terakhir dan saya ingin setepat mungkin.
Saya telah membaca bahwa ada beberapa masalah resolusi waktu yang serius antara sistem operasi yang berbeda (yaitu bahwa Mac / Linux memiliki resolusi hampir 1 ms sementara Windows memiliki resolusi 50 ms ??). Saya terutama menjalankan aplikasi saya di windows dan resolusi 50ms tampaknya cukup tidak akurat.
Apakah ada opsi yang lebih baik daripada dua yang saya daftarkan?
Ada saran / komentar?
java
timer
time-precision
mmcdole
sumber
sumber
nanoTime
secara signifikan biasanya lebih akurat daripada currentTimeMillis tetapi ini adalah panggilan yang relatif mahal juga.currentTimeMillis()
berjalan dalam beberapa (5-6) jam cpu, nanoTime tergantung pada arsitektur yang mendasarinya dan bisa 100 jam cpu.System.currentTimeMillis()
: pzemtsov.github.io/2017/07/23/the-slow-currenttimemillis.htmlJawaban:
Jika Anda hanya mencari pengukuran waktu berlalu yang sangat tepat , gunakan
System.nanoTime()
.System.currentTimeMillis()
akan memberi Anda waktu berlalu yang paling akurat dalam milidetik sejak zaman itu, tetapiSystem.nanoTime()
memberi Anda waktu yang tepat nanodetik, relatif terhadap beberapa titik yang berubah-ubah.Dari Dokumentasi Java:
Misalnya, untuk mengukur berapa lama beberapa kode diperlukan untuk dieksekusi:
Lihat juga: JavaDoc System.nanoTime () dan JavaDoc System.currentTimeMillis () untuk info lebih lanjut.
sumber
currentTimeMillis
berubah karena DST? Sakelar DST tidak mengubah jumlah detik melewati zaman. Ini mungkin merupakan "jam dinding" tetapi ini didasarkan pada UTC. Anda harus menentukan berdasarkan zona waktu Anda dan pengaturan DST apa yang diterjemahkan untuk waktu lokal Anda (atau menggunakan utilitas Java lainnya untuk melakukannya untuk Anda).Karena tidak ada orang lain yang menyebutkan ini ...
Tidaklah aman untuk membandingkan hasil
System.nanoTime()
panggilan di antara berbagai utas. Bahkan jika peristiwa thread terjadi dalam urutan yang dapat diprediksi, perbedaan dalam nanodetik bisa positif atau negatif.System.currentTimeMillis()
aman untuk digunakan di antara utas.sumber
The values returned by this method become meaningful only when the difference between two such values, obtained within the same instance of a Java virtual machine, is computed.
nanoTime()
mengatakan: Asal yang sama digunakan oleh semua doa metode ini dalam mesin virtual Java; contoh mesin virtual lainnya cenderung menggunakan asal yang berbeda. yang berarti bahwa itu tidak kembali sama di thread.Pembaruan oleh Arkadiy : Saya telah mengamati perilaku yang lebih benar
System.currentTimeMillis()
pada Windows 7 di Oracle Java 8. Waktu dikembalikan dengan presisi 1 milidetik. Kode sumber di OpenJDK belum berubah, jadi saya tidak tahu apa yang menyebabkan perilaku yang lebih baik.David Holmes dari Sun memposting artikel blog beberapa tahun yang lalu yang memiliki tampilan yang sangat rinci pada Java timing APIs (khususnya
System.currentTimeMillis()
danSystem.nanoTime()
), ketika Anda ingin menggunakan yang mana, dan bagaimana mereka bekerja secara internal.Di dalam Hotspot VM: Jam, Timer dan Acara Penjadwalan - Bagian I - Windows
Satu aspek yang sangat menarik dari penghitung waktu yang digunakan oleh Java pada Windows untuk API yang memiliki parameter waktu tunggu adalah bahwa resolusi penghitung waktu dapat berubah tergantung pada apa panggilan API lain yang mungkin telah dibuat - sistem lebar (tidak hanya dalam proses tertentu) . Dia menunjukkan contoh di mana penggunaan
Thread.sleep()
akan menyebabkan resolusi ini berubah.sumber
GetSystemTimeAsFileTime
kerja di XP vs 7. Lihat di sini untuk detail lebih lanjut (t; dr itu menjadi lebih tepat karena seluruh sistem memperkenalkan beberapa metode waktu yang lebih tepat).System.nanoTime()
tidak didukung di JVM yang lebih lama. Jika itu masalah, tetaplah dengancurrentTimeMillis
Mengenai akurasi, Anda hampir benar. Pada BEBERAPA mesin Windows,
currentTimeMillis()
memiliki resolusi sekitar 10 ms (bukan 50 ms). Saya tidak yakin mengapa, tetapi beberapa mesin Windows sama akuratnya dengan mesin Linux.Saya telah menggunakan GAGETimer di masa lalu dengan kesuksesan sedang.
sumber
Seperti yang dikatakan orang lain, currentTimeMillis adalah waktu jam, yang berubah karena waktu musim panas, pengguna mengubah pengaturan waktu, detik kabisat, dan sinkronisasi waktu internet. Jika aplikasi Anda bergantung pada peningkatan nilai waktu yang berlalu secara monoton, Anda mungkin lebih memilih nanoTime.
Anda mungkin berpikir bahwa para pemain tidak akan mengutak-atik pengaturan waktu selama bermain game, dan mungkin Anda akan benar. Tetapi jangan meremehkan gangguan karena sinkronisasi waktu internet, atau mungkin pengguna desktop jarak jauh. API nanoTime kebal terhadap gangguan semacam ini.
Jika Anda ingin menggunakan waktu jam, tetapi menghindari diskontinuitas karena sinkronisasi waktu internet, Anda dapat mempertimbangkan klien NTP seperti Meinberg, yang "menyetel" laju jam ke nol, bukan hanya mengatur ulang jam secara berkala.
Saya berbicara dari pengalaman pribadi. Dalam aplikasi cuaca yang saya kembangkan, saya mendapatkan lonjakan kecepatan angin secara acak. Butuh beberapa saat bagi saya untuk menyadari bahwa basis waktu saya sedang terganggu oleh perilaku waktu jam pada PC biasa. Semua masalah saya hilang ketika saya mulai menggunakan nanoTime. Konsistensi (monotonisitas) lebih penting bagi aplikasi saya daripada presisi mentah atau akurasi absolut.
sumber
System.currentTimeMillis()
melaporkan waktu yang telah berlalu (dalam milidetik) sejak Zaman Unix / Posix yaitu Tengah Malam, 1 Januari 1970 UTC. Karena UTC tidak pernah disesuaikan untuk penghematan siang hari, nilai ini tidak akan diimbangi ketika zona waktu lokal menambah atau tunduk pada waktu lokal untuk penghematan siang hari. Selain itu, Skala Waktu Jawa memuluskan detik kabisat sehingga hari-hari terus tampak memiliki 86.400 detik.Ya, jika ketepatan seperti itu diperlukan penggunaan
System.nanoTime()
, tetapi perlu diketahui bahwa Anda kemudian memerlukan Java 5+ JVM.Pada sistem XP saya, saya melihat waktu sistem yang dilaporkan setidaknya
100 mikrodetik278 nanodetik menggunakan kode berikut:sumber
Untuk grafik game & pembaruan posisi halus, gunakan
System.nanoTime()
alih-alihSystem.currentTimeMillis()
. Saya beralih dari currentTimeMillis () ke nanoTime () dalam sebuah game dan mendapat peningkatan visual utama dalam kelancaran gerak.Sementara satu milidetik mungkin tampak seolah-olah seharusnya sudah tepat, secara visual tidak. Faktor-faktor yang
nanoTime()
dapat ditingkatkan termasuk:Seperti jawaban lain yang disarankan, nanoTime memang memiliki biaya kinerja jika dipanggil berulang kali - akan lebih baik untuk memanggilnya hanya sekali per frame, dan menggunakan nilai yang sama untuk menghitung seluruh frame.
sumber
Saya sudah memiliki pengalaman yang baik dengan nanotime . Ini menyediakan waktu jam dinding sebagai dua long (detik sejak zaman dan nanodetik dalam detik itu), menggunakan perpustakaan JNI. Ini tersedia dengan bagian JNI yang dikompilasi untuk Windows dan Linux.
sumber
System.currentTimeMillis()
tidak aman untuk waktu yang berlalu karena metode ini peka terhadap perubahan sistem waktu nyata sistem. Anda harus menggunakanSystem.nanoTime
. Silakan lihat bantuan Sistem Java:Tentang metode nanoTime:
Jika Anda menggunakan
System.currentTimeMillis()
waktu yang Anda lewati bisa negatif (Kembali <- ke masa depan)sumber
satu hal di sini adalah inkonsistensi metode nanoTime. itu tidak memberikan nilai yang sangat konsisten untuk input yang sama .currentTimeMillis melakukan jauh lebih baik dalam hal kinerja dan konsistensi, dan juga, meskipun tidak setepat nanoTime, memiliki margin kesalahan yang lebih rendah , dan karena itu lebih akurat nilainya. Karena itu saya menyarankan agar Anda menggunakan currentTimeMillis
sumber