Dokładność vs. Precyzja
Chciałbym wiedzieć, czy powinienem używać System.currentTimeMillis () czy System.nanoTime () podczas aktualizacji pozycji mojego obiektu w mojej grze? Ich zmiana ruchu jest wprost proporcjonalna do czasu, jaki upłynął od ostatniego połączenia i chcę być tak precyzyjny, jak to możliwe.
Czytałem, że istnieją poważne problemy z rozdzielczością czasową między różnymi systemami operacyjnymi (mianowicie, że Mac / Linux ma rozdzielczość prawie 1 ms, podczas gdy Windows ma rozdzielczość 50ms ??). Głównie uruchamiam moje aplikacje w systemie Windows, a rozdzielczość 50 ms wydaje się dość niedokładna.
Czy są lepsze opcje niż dwie wymienione na liście?
Wszelkie sugestie / komentarze?
java
timer
time-precision
mmcdole
źródło
źródło
nanoTime
jest zwykle znacznie bardziej dokładny niż currentTimeMillis, ale jest to również stosunkowo droga rozmowa.currentTimeMillis()
działa na kilku (5-6) zegarach procesora, nanoTime zależy od podstawowej architektury i może wynosić ponad 100 zegarów procesora.System.currentTimeMillis()
: pzemtsov.github.io/2017/07/23/the-slow-currenttimemillis.htmlOdpowiedzi:
Jeśli szukasz bardzo precyzyjnych pomiarów upływającego czasu , użyj
System.nanoTime()
.System.currentTimeMillis()
da ci najdokładniejszy możliwy upływ czasu w milisekundach od epoki, aleSystem.nanoTime()
da ci nanosekundowy czas w stosunku do dowolnego dowolnego punktu.Z dokumentacji Java:
Na przykład, aby zmierzyć, ile czasu zajmuje wykonanie kodu:
Zobacz także: JavaDoc System.nanoTime () i JavaDoc System.currentTimeMillis (), aby uzyskać więcej informacji.
źródło
currentTimeMillis
zmieniać z powodu DST? Przełącznik DST nie zmienia liczby sekund po epoce. Może to być „zegar ścienny”, ale jest on oparty na UTC. Na podstawie strefy czasowej i ustawień czasu letniego musisz określić, co przekłada się na twój czas lokalny (lub użyj innych narzędzi Java, aby to zrobić za Ciebie).Ponieważ nikt inny nie wspomniał o tym ...
Porównywanie wyników
System.nanoTime()
połączeń między różnymi wątkami nie jest bezpieczne . Nawet jeśli zdarzenia wątków przebiegają w przewidywalnej kolejności, różnica w nanosekundach może być dodatnia lub ujemna.System.currentTimeMillis()
jest bezpieczny w użyciu między wątkami.źródło
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()
mówi: To samo pochodzenie jest używane przez wszystkie wywołania tej metody w wystąpieniu wirtualnej maszyny Java; inne instancje maszyn wirtualnych prawdopodobnie będą miały inne pochodzenie. co oznacza, że nie zwraca te same całej wątków.Aktualizacja autorstwa Arkadiy : Zauważyłem bardziej prawidłowe zachowanie
System.currentTimeMillis()
systemu Windows 7 w Oracle Java 8. Czas został zwrócony z dokładnością do 1 milisekundy. Kod źródłowy w OpenJDK nie zmienił się, więc nie wiem, co powoduje lepsze zachowanie.David Holmes z firmy Sun opublikował kilka lat temu artykuł na blogu, który bardzo szczegółowo omawia interfejsy API synchronizacji Java (w szczególności
System.currentTimeMillis()
iSystem.nanoTime()
), kiedy chcesz z nich korzystać i jak działają one wewnętrznie.Wewnątrz maszyny Wirtualnej Hotspot: Zegary, zegary i planowanie zdarzeń - Część I - Windows
Jednym z bardzo interesujących aspektów timera używanego przez Javę w systemie Windows do interfejsów API z parametrem timed wait jest to, że rozdzielczość timera może się zmieniać w zależności od tego, jakie inne wywołania API mogły zostać wykonane - w całym systemie (nie tylko w konkretnym procesie) . Pokazuje przykład, w którym użycie
Thread.sleep()
spowoduje zmianę rozdzielczości.źródło
GetSystemTimeAsFileTime
pracował w XP vs 7. Zobacz tutaj po więcej szczegółów (TL; dr zrobiło się bardziej precyzyjne, ponieważ cały system wprowadził pewne bardziej precyzyjnych metod pomiaru czasu).System.nanoTime()
nie jest obsługiwany w starszych JVM. Jeśli jest to problem, trzymaj sięcurrentTimeMillis
Jeśli chodzi o dokładność, masz prawie rację. Na NIEKTÓRYCH komputerach z systemem Windows
currentTimeMillis()
ma rozdzielczość około 10 ms (nie 50 ms). Nie jestem pewien, dlaczego, ale niektóre maszyny z systemem Windows są tak samo dokładne, jak maszyny z systemem Linux.W przeszłości używałem GAGETimeru z umiarkowanym sukcesem.
źródło
Jak powiedzieli inni, currentTimeMillis to czas zegarowy, który zmienia się z powodu czasu letniego, użytkowników zmieniających ustawienia czasu, sekund przestępnych i synchronizacji czasu internetowego. Jeśli Twoja aplikacja zależy od monotonicznie rosnących wartości upływającego czasu, możesz zamiast tego preferować nanoTime.
Możesz myśleć, że gracze nie będą majstrować przy ustawieniach czasu podczas gry, a może masz rację. Ale nie należy lekceważyć zakłóceń spowodowanych synchronizacją czasu w Internecie lub być może zdalnych użytkowników komputerów stacjonarnych. Interfejs API nanoTime jest odporny na tego rodzaju zakłócenia.
Jeśli chcesz użyć czasu zegara, ale uniknąć nieciągłości z powodu synchronizacji czasu w Internecie, możesz rozważyć klienta NTP, takiego jak Meinberg, który „dostosowuje” częstotliwość zegara, aby ją wyzerować, zamiast okresowego resetowania zegara.
Mówię z własnego doświadczenia. W opracowanej przeze mnie aplikacji pogodowej dostawałem przypadkowo gwałtowne skoki prędkości wiatru. Zajęło mi trochę czasu, zanim zdałem sobie sprawę, że moja podstawa czasu została zakłócona przez zachowanie czasu na typowym komputerze. Wszystkie moje problemy zniknęły, kiedy zacząłem używać nanoTime. Spójność (monotoniczność) była ważniejsza dla mojej aplikacji niż surowa precyzja lub absolutna dokładność.
źródło
System.currentTimeMillis()
zgłasza upływ czasu (w milisekundach) od Epoki Uniksa / Posixa, czyli o północy, 1 stycznia 1970 UTC. Ponieważ UTC nigdy nie jest korygowane o czas letni, ta wartość nie zostanie przesunięta, gdy lokalne strefy czasowe dodadzą lub poddadzą przesunięcie czasowi lokalnemu o czas letni. Co więcej, Java Time Scale wygładza sekundy przestępne, dzięki czemu dni wydają się mieć 86 400 sekund.Tak, jeśli taka precyzja jest wymagana, użyj
System.nanoTime()
, ale pamiętaj, że potrzebujesz JVM Java 5+.W moich systemach XP widzę czas systemowy zgłaszany do co najmniej
100 mikrosekund278 nanosekund przy użyciu następującego kodu:źródło
Do grafiki gry i płynnych aktualizacji pozycji użyj
System.nanoTime()
raczej niżSystem.currentTimeMillis()
. W grze przeszedłem z currentTimeMillis () na nanoTime () i uzyskałem znaczną poprawę płynności ruchu.Choć jedna milisekunda może wydawać się, że powinna być już dokładna, wizualnie tak nie jest. Czynniki, które
nanoTime()
można poprawić, obejmują:Jak sugerują inne odpowiedzi, nanoTime ma koszt wydajności, jeśli jest wywoływany wielokrotnie - najlepiej byłoby wywołać go tylko raz na ramkę i użyć tej samej wartości do obliczenia całej ramki.
źródło
Mam dobre doświadczenie z nanotime . Zapewnia czas zegara ściennego jako dwie długości (sekundy od epoki i nanosekundy w tej sekundzie), przy użyciu biblioteki JNI. Jest dostępny ze wstępnie skompilowaną częścią JNI dla Windows i Linux.
źródło
System.currentTimeMillis()
nie jest bezpieczny dla upływu czasu, ponieważ ta metoda jest wrażliwa na zmiany systemu w czasie rzeczywistym. Powinieneś użyćSystem.nanoTime
. Zapoznaj się z pomocą systemu Java:O metodzie nanoTime:
Jeśli wykorzystasz
System.currentTimeMillis()
czas, który upłynął, może być ujemny (wstecz <- do przyszłości)źródło
jedną rzeczą tutaj jest niespójność metody nanoTime. nie daje bardzo spójnych wartości dla tego samego wejścia. prąd bieżący Millis ma znacznie lepszą wydajność i spójność, a także, choć nie tak precyzyjny jak nanoTime, ma niższy margines błędu , a tym samym większą dokładność jego wartości. sugerowałbym zatem użycie currentTimeMillis
źródło