Jak udokumentowano w poście na blogu Beware of System.nanoTime () w Javie , w systemach x86 Java's System.nanoTime () zwraca wartość czasu przy użyciu licznika specyficznego dla procesora . Rozważmy teraz następujący przypadek, którego używam do mierzenia czasu połączenia:
long time1= System.nanoTime();
foo();
long time2 = System.nanoTime();
long timeSpent = time2-time1;
Teraz w systemie wielordzeniowym może się zdarzyć, że po pomiarze czasu1 wątek zostanie zaplanowany dla innego procesora, którego licznik jest mniejszy niż poprzedni procesor. W ten sposób moglibyśmy otrzymać wartość w time2, która jest mniejsza niż time1. W ten sposób otrzymalibyśmy ujemną wartość czasu spędzonego.
Biorąc pod uwagę ten przypadek, czy nie jest tak, że System.nanotime jest obecnie prawie bezużyteczny?
Wiem, że zmiana czasu systemowego nie wpływa na nanotime. To nie jest problem, który opisałem powyżej. Problem polega na tym, że każdy procesor od momentu włączenia będzie utrzymywał inny licznik. Ten licznik może być niższy na drugim procesorze w porównaniu z pierwszym procesorem. Ponieważ wątek może zostać zaplanowany przez system operacyjny do drugiego procesora po uzyskaniu time1, wartość timeSpent może być niepoprawna, a nawet ujemna.
Odpowiedzi:
Ta odpowiedź została napisana w 2011 roku z punktu widzenia tego, co faktycznie robił Sun JDK tamtego czasu działający na systemach operacyjnych w tamtym czasie. To było bardzo dawno temu! Odpowiedź Leventova oferuje bardziej aktualną perspektywę.
Ten post jest zły i
nanoTime
jest bezpieczny. Istnieje komentarz do posta, który zawiera odsyłacze do posta na blogu Davida Holmesa , specjalisty ds. Czasu rzeczywistego i współbieżności w firmie Sun. To mówi:Tak więc w systemie Windows był to problem aż do WinXP SP2, ale teraz nie jest.
Nie mogę znaleźć części II (lub więcej), która mówi o innych platformach, ale ten artykuł zawiera uwagę, że Linux napotkał i rozwiązał ten sam problem w ten sam sposób, z linkiem do FAQ dla clock_gettime (CLOCK_REALTIME) , który mówi:
Tak więc, jeśli link Holmesa można odczytać jako sugerujący, że
nanoTime
wywołujeclock_gettime(CLOCK_REALTIME)
, to jest bezpieczny od jądra 2.6.18 na x86 i zawsze na PowerPC (ponieważ IBM i Motorola, w przeciwieństwie do Intela, faktycznie wiedzą, jak projektować mikroprocesory).Niestety nie ma wzmianki o SPARC czy Solarisie. I oczywiście nie mamy pojęcia, co robią maszyny JVM IBM. Jednak maszyny JVM firmy Sun w nowoczesnych systemach Windows i Linux radzą sobie dobrze.
EDYCJA: Ta odpowiedź jest oparta na źródłach, które cytuje. Ale nadal martwię się, że może to być całkowicie błędne. Niektóre bardziej aktualne informacje byłyby naprawdę cenne. Właśnie trafiłem na link do nowszego o cztery lata artykułu o zegarach Linuksa, który może być przydatny.
źródło
void foo() { Thread.sleep(40); }
mam czas ujemny (-380 ms!) Za pomocą jednegoAthlon 64 X2 4200+
procesoraPoszukałem trochę i stwierdziłem, że jeśli ktoś jest pedantyczny, to tak, może to zostać uznane za bezużyteczne ... w określonych sytuacjach ... zależy to od tego, jak wrażliwe są twoje wymagania ...
Sprawdź ten cytat z witryny Java Sun:
Java ma również zastrzeżenie dotyczące metody nanoTime () :
Wydawałoby się, że jedynym wnioskiem, jaki można wyciągnąć, jest to, że nanoTime () nie może być traktowane jako dokładna wartość. W związku z tym, jeśli nie musisz mierzyć czasów, które są oddalone od siebie zaledwie o nano sekundy, ta metoda jest wystarczająco dobra, nawet jeśli wynikowa zwrócona wartość jest ujemna. Jeśli jednak potrzebujesz większej precyzji, wydaje się, że zalecają korzystanie z JAVA RTS.
A więc odpowiadając na twoje pytanie ... żadna nanoTime () nie jest bezużyteczna ... po prostu nie jest to najrozsądniejsza metoda w każdej sytuacji.
źródło
-100
,-99
,-98
(Oczywiście znacznie większe wartości w praktyce). Idą we właściwym kierunku (rosną), więc nie ma tu problemu.Nie ma potrzeby debatowania, po prostu użyj źródła. Tutaj, SE 6 dla Linuksa, wyciągnij własne wnioski:
źródło
Od wersji Java 7,
System.nanoTime()
specyfikacja JDK gwarantuje bezpieczeństwo.System.nanoTime()
Javadoc wyjaśnia, że wszystkie obserwowane wywołania w JVM (to znaczy we wszystkich wątkach) są monotoniczne:Implementacja JVM / JDK jest odpowiedzialna za wyeliminowanie niespójności, które można zaobserwować, gdy wywoływane są podstawowe narzędzia systemu operacyjnego (np. Te wymienione w odpowiedzi Toma Andersona ).
Większość innych starych odpowiedzi na to pytanie (napisanych w latach 2009–2012) wyraża FUD, który prawdopodobnie był istotny dla Javy 5 lub Javy 6, ale nie ma już znaczenia dla nowoczesnych wersji Javy.
Warto jednak wspomnieć, że pomimo gwarancji
nanoTime()
bezpieczeństwa JDK , w OpenJDK było kilka błędów powodujących, że nie dotrzymuje on tej gwarancji na niektórych platformach lub w pewnych okolicznościach (np. JDK-8040140 , JDK-8184271 ). W tej chwili nie ma żadnych otwartych (znanych) błędów w OpenJDK wrtnanoTime()
, ale odkrycie nowego takiego błędu lub regresja w nowszej wersji OpenJDK nie powinno nikogo zszokować.Mając to na uwadze, kod, który używa
nanoTime()
do blokowania czasowego, oczekiwania na interwał, przekroczenia limitu czasu itp. Powinien raczej traktować ujemne różnice czasu (limity czasu) jako zera, a nie zgłaszać wyjątki. Praktyka ta jest również korzystna, ponieważ jest zgodna z zachowaniem wszystkich zsynchronizowanych metod czekać w wszystkich klasach wjava.util.concurrent.*
, na przykładSemaphore.tryAcquire()
,Lock.tryLock()
,BlockingQueue.poll()
, itd.Niemniej jednak
nanoTime()
nadal powinno być preferowane do implementacji blokowania czasowego, oczekiwania interwałowego, przekroczenia limitów czasu itp.,currentTimeMillis()
Ponieważ to ostatnie podlega zjawisku „cofania się czasu” (np. Z powodu korekty czasu serwera), tj.currentTimeMillis()
Nie nadaje się do pomiaru odstępów czasu w ogóle. Zobacz tę odpowiedź, aby uzyskać więcej informacji.Zamiast używać
nanoTime()
do bezpośredniego pomiaru czasu wykonania kodu, najlepiej używać wyspecjalizowanych frameworków do benchmarkingu i profilerów, na przykład JMH i async-profiler w trybie profilowania zegara ściennego .źródło
Zastrzeżenie: jestem twórcą tej biblioteki
Może ci się to bardziej spodobać:
http://juliusdavies.ca/nanotime/
Ale kopiuje plik DLL lub Unix .so (obiekt współdzielony) do katalogu domowego bieżącego użytkownika, aby mógł wywołać JNI.
W mojej witrynie pod adresem:
http://juliusdavies.ca/posix_clocks/clock_realtime_linux_faq.html
źródło
Linux koryguje rozbieżności między procesorami, ale Windows nie. Sugeruję, abyś założył, że System.nanoTime () ma dokładność tylko do około 1 mikro-sekundy. Prostym sposobem na uzyskanie dłuższego czasu jest wywołanie funkcji foo () 1000 lub więcej razy i podzielenie czasu przez 1000.
źródło
Absolutnie nie bezużyteczne. Miłośnicy pomiaru czasu poprawnie wskazują na problem wielordzeniowy, ale w aplikacjach używających rzeczywistych słów często jest on radykalnie lepszy niż currentTimeMillis ().
Podczas obliczania pozycji grafiki w ramkach odświeżanie nanoTime () prowadzi do DUŻO płynniejszego ruchu w moim programie.
Testuję tylko na maszynach wielordzeniowych.
źródło
Widziałem ujemny czas, który upłynął od użycia System.nanoTime (). Żeby było jasne, kod, o którym mowa, to:
a zmienna „elapsedNanos” miała wartość ujemną. (Jestem pewien, że połączenie pośrednie również zajęło mniej niż 293 lata, co jest punktem przepełnienia dla nanos przechowywanych w długich długościach :)
Nastąpiło to przy użyciu 64-bitowego środowiska IBM JRE 1.5 na sprzęcie IBM P690 (wielordzeniowym) z systemem AIX. Widziałem ten błąd tylko raz, więc wydaje się niezwykle rzadki. Nie znam przyczyny - czy jest to problem specyficzny dla sprzętu, wada JVM - nie wiem. Nie znam też ogólnych implikacji dla dokładności nanoTime ().
Odpowiadając na pierwotne pytanie, nie sądzę, że nanoTime jest bezużyteczny - zapewnia czas poniżej milisekundy, ale istnieje rzeczywiste (nie tylko teoretyczne) ryzyko, że będzie niedokładny, co należy wziąć pod uwagę.
źródło
Nie wydaje się to być problemem na Core 2 Duo z systemem Windows XP i JRE 1.5.0_06.
W teście z trzema wątkami nie widzę System.nanoTime () przechodzącego wstecz. Procesory są zajęte, a wątki czasami zasypiają, aby sprowokować poruszające się wątki.
[EDYCJA] Wydaje mi się, że dzieje się tak tylko na fizycznie oddzielnych procesorach, tj. Liczniki są zsynchronizowane dla wielu rdzeni na tej samej matrycy.
źródło
Nie, to nie jest ... To zależy tylko od twojego procesora, sprawdź High Precision Event Timer, aby dowiedzieć się, jak / dlaczego różne rzeczy są traktowane w zależności od procesora.
Zasadniczo przeczytaj źródło swojej Javy i sprawdź, co robi twoja wersja z funkcją i czy działa przeciwko procesorowi, na którym będziesz ją uruchamiać.
IBM sugeruje nawet użycie go do testów porównawczych wydajności (post z 2008 roku, ale zaktualizowany).
źródło
Nawiązuję do tego, co zasadniczo jest tą samą dyskusją, w której Peter Lawrey udziela dobrej odpowiedzi. Dlaczego przy użyciu System.nanoTime () otrzymuję ujemny czas, który upłynął?
Wiele osób wspomniało, że w Java System.nanoTime () może zwracać czas ujemny. Przepraszam za powtórzenie tego, co powiedzieli już inni.
Byłoby fajnie, gdyby System.nanoTime () zwrócił coreID tam, gdzie został wykonany.
źródło
Java jest wieloplatformowa, a nanoTime jest zależna od platformy. Jeśli używasz Javy - kiedy nie używaj nanoTime. Znalazłem prawdziwe błędy w różnych implementacjach jvm z tą funkcją.
źródło
Dokumentacja Java 5 również zaleca użycie tej metody w tym samym celu.
Dokumentacja API Java 5
źródło
Ponadto
System.currentTimeMillies()
zmienia się po zmianie zegara systemy, aSystem.nanoTime()
nie, więc ten ostatni jest bezpieczniej zmierzyć czas trwania.źródło
nanoTime
jest wyjątkowo niepewny czas. Wypróbowałem to na moich podstawowych algorytmach testowania pierwotności i dało odpowiedzi, które były dosłownie o jedną sekundę oddalone dla tego samego wejścia. Nie używaj tej śmiesznej metody. Potrzebuję czegoś, co jest dokładniejsze i dokładniejsze niż mierzenie milisekund czasu, ale nie tak złe jaknanoTime
.źródło