System.currentTimeMillis बनाम System.nanoTime


379

सटीकता बनाम। शुद्धता

मैं जानना चाहूंगा कि क्या मुझे अपने खेल में अपने ऑब्जेक्ट की स्थिति को अपडेट करते समय System.currentTimeMillis () या System.nanoTime () का उपयोग करना चाहिए ? आंदोलन में उनका परिवर्तन अंतिम कॉल के बाद से बीता समय के लिए सीधे आनुपातिक है और मैं यथासंभव सटीक होना चाहता हूं।

मैंने पढ़ा है कि विभिन्न ऑपरेटिंग सिस्टमों के बीच कुछ गंभीर समय-रिज़ॉल्यूशन समस्याएं हैं (अर्थात मैक / लिनक्स में लगभग 1 एमएस रिज़ॉल्यूशन है जबकि विंडोज में 50ms रिज़ॉल्यूशन है)? मैं मुख्य रूप से विंडोज़ और 50ms रिज़ॉल्यूशन पर अपने ऐप चला रहा हूं, बहुत गलत लगता है।

क्या मेरे द्वारा सूचीबद्ध दो से बेहतर विकल्प हैं?

कोई सुझाव / टिप्पणी?


81
nanoTimeकरंट टाइममिलिस की तुलना में आमतौर पर अधिक सटीक होता है, लेकिन यह अपेक्षाकृत महंगा कॉल भी है। currentTimeMillis()कुछ (5-6) सीपीयू घड़ियों में चलाता है, नैनो टाइम अंतर्निहित वास्तुकला पर निर्भर करता है और 100+ सीपीयू घड़ियों हो सकता है।
bestsss

10
आप सभी को पता है कि विंडोज में आमतौर पर 1000ms / 64 का टाइमलाइन ग्रैन्युलैरिटी होता है, है ना? जो कि 15.625ms, या 15625000nanoseconds है!

7
मुझे नहीं लगता कि सौ अतिरिक्त घड़ी चक्र आपके खेल को प्रभावित करने वाले हैं, और व्यापार बंद शायद इसके लायक होगा। आपको केवल गेम अपडेट के अनुसार एक बार मेथड को कॉल करना चाहिए, फिर मेम को सेव करना होगा, इसलिए यह बहुत अधिक ओवरहेड नहीं जोड़ेगा। विभिन्न प्लेटफार्मों की ग्रैन्युलैरिटी के लिए मेरे पास कोई विचार नहीं है।
एग्लासमैन

9
विंडोज में 1000ms / 64 की DEFAULT timeslice ग्रैन्युलैरिटी है। आप इसे देशी समयबिनपिरियोड एपीआई के माध्यम से बढ़ा सकते हैं। आधुनिक पीसी में मूल टाइमर के अलावा उच्च-रिज़ॉल्यूशन टाइमर भी होते हैं। उच्च-रिज़ॉल्यूशन टाइमर QueryPerformanceCounter कॉल के माध्यम से सुलभ हैं।
रॉबिन डेविस

2
@Gohan - यह लेख भीतर के कामकाज के बारे में विस्तार से बताता है System.currentTimeMillis(): pzemtsov.github.io/2017/07/23/the-slow-currenttimemillis.html
Attila Tanyi

जवाबों:


320

यदि आप अभी बेहद सटीक माप की तलाश में हैं बीते हुए समय के , तो उपयोग करें System.nanoTime()System.currentTimeMillis()आपको युग के बाद से मिलीसेकंड में सबसे सटीक संभव बीता हुआ समय देगा, लेकिन System.nanoTime()कुछ मनमाना बिंदु के सापेक्ष आपको नैनोसेकंड-सटीक समय देता है।

जावा प्रलेखन से:

public static long nanoTime()

सबसे सटीक उपलब्ध सिस्टम टाइमर के वर्तमान मूल्य को नैनोसेकंड में लौटाता है।

इस पद्धति का उपयोग केवल बीते हुए समय को मापने के लिए किया जा सकता है और सिस्टम या दीवार-घड़ी के समय की किसी अन्य धारणा से संबंधित नहीं है। लौटाया गया मान कुछ निश्चित लेकिन मनमाना मूल समय (शायद भविष्य में, इसलिए मान नकारात्मक हो सकता है) के बाद से नैनोसेकंड का प्रतिनिधित्व करता है । यह विधि नैनोसेकंड सटीक प्रदान करती है, लेकिन जरूरी नहीं कि नैनोसेकंड सटीकता। मान कितनी बार बदलते हैं, इसकी कोई गारंटी नहीं है। लगभग 292 वर्षों (2 63 नैनोसेकंड) से अधिक की अवधि वाली लगातार कॉल में अंतर संख्यात्मक अतिप्रवाह के कारण बीते हुए समय की सही गणना नहीं करेगा।

उदाहरण के लिए, यह मापने के लिए कि किसी कोड को निष्पादित करने में कितना समय लगता है:

long startTime = System.nanoTime();    
// ... the code being measured ...    
long estimatedTime = System.nanoTime() - startTime;

यह भी देखें: अधिक जानकारी के लिए JavaDoc System.nanoTime () और JavaDoc System.currentTimeMillis ()


20
क्या आप सुनिश्चित हैं कि आप सटीकता और सटीकता के बीच अंतर जानते हैं? कोई रास्ता नहीं है यह एक नैनोसेकंड सटीक के लिए सटीक है।
mmcdole

6
क्षमा करें, मेरा मतलब सटीक था। मैं इस शब्द का उपयोग शिथिल कर रहा था, लेकिन मैं मानता हूं कि यह भ्रामक था (और शब्द का अनुचित उपयोग)।
dancavallaro

4
@dancavallaro, जानकारी के लिए धन्यवाद। अगर आपको कोई आपत्ति नहीं है, तो मैंने डॉक्स से एक उद्धरण शामिल करने के लिए आपके उत्तर को संपादित किया और लिंक को ठीक किया
mmcdole

135
यह उत्तर तकनीकी रूप से नैनोटाइम () चुनने में सही है लेकिन एक अत्यंत महत्वपूर्ण बिंदु पर पूरी तरह से चमकता है। नैनो टाइम (), जैसा कि डॉक्टर कहते हैं, एक सटीक टाइमर है। currentTimeMillis () A TIMER नहीं है, यह "वॉल क्लॉक" है। nanoTime () हमेशा सकारात्मक बीता हुआ समय पैदा करेगा, currentTimeMillis नहीं होगा (जैसे यदि आप तारीख बदलते हैं, तो एक छलांग दूसरे नंबर पर मारते हैं, आदि) यह कुछ प्रकार के सिस्टम के लिए एक अत्यंत महत्वपूर्ण अंतर है।
charstar

11
उपयोगकर्ता के बदलते समय और NTP में सिंक होना निश्चित है, लेकिन currentTimeMillisDST के कारण क्यों बदल जाएगा ? डीएसटी स्विच युग के पिछले कुछ सेकंड नहीं बदलता है। यह एक "दीवार घड़ी" हो सकती है, लेकिन यह यूटीसी पर आधारित है। आपको अपने टाइमज़ोन और डीएसटी सेटिंग्स के आधार पर निर्धारित करना होगा कि आपके स्थानीय समय के लिए क्या अनुवाद करता है (या आपके लिए ऐसा करने के लिए अन्य जावा उपयोगिताओं का उपयोग करें)।
शैडो मैन

100

चूंकि किसी और ने इसका उल्लेख नहीं किया है ...

System.nanoTime()विभिन्न थ्रेड्स के बीच कॉल के परिणामों की तुलना करना सुरक्षित नहीं है । यहां तक ​​कि अगर थ्रेड्स की घटनाएं एक पूर्वानुमान क्रम में होती हैं, तो नैनोसेकंड में अंतर सकारात्मक या नकारात्मक हो सकता है।

System.currentTimeMillis() धागे के बीच उपयोग के लिए सुरक्षित है।


4
Windows पर जो केवल SP2 के अनुसार तब तक रखता है: stackoverflow.com/questions/510462/…
पीटर श्मिट

3
हां, आप हर दिन कुछ नया सीखते हैं। मुझे संदेह है, हालांकि, यह देखते हुए कि यह अतीत में असुरक्षित था (निश्चित रूप से धागे के पार बकवास रीडिंग देता है), इस तरह का उपयोग संभवतः अभी भी कल्पना के बाहर है और इसलिए शायद इसे टाला जाना चाहिए।
गब्बी

4
@jgubby: बहुत दिलचस्प ... समर्थन का कोई संदर्भ जो अलग-अलग थ्रेड्स के बीच System.nanoTime () कॉल के परिणामों की तुलना करने के लिए सुरक्षित नहीं है ? निम्नलिखित लिंक देखने लायक हैं: Bugs.sun.com/bugdatabase/view_bug.do?bug_id=6519418 docs.oracle.com/javase/7/docs/api/java/lang-…
user454322

15
यहाँ वर्णित विवरण को देखते हुए: docs.oracle.com/javase/7/docs/api/java/lang/… , ऐसा लगता है कि नैनोटाइम से लौटाए गए मूल्यों के बीच का अंतर तुलना के लिए मान्य है जब तक वे उसी से थे JVM -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.
Tuxdude

7
जावाडॉकnanoTime() कहता है: जावा वर्चुअल मशीन के उदाहरण में एक ही मूल का उपयोग इस पद्धति के सभी चालानों द्वारा किया जाता है; अन्य वर्चुअल मशीन इंस्टेंस एक अलग मूल का उपयोग करने की संभावना है। जिसका अर्थ है कि यह करता है धागे में एक ही लौट आते हैं।
साइमन फोर्सबर्ग 16

58

अरकडिया द्वारा अपडेट : मैंने System.currentTimeMillis()ओरेकल जावा 8 में विंडोज 7 पर अधिक सही व्यवहार देखा है । समय को 1 मिलीसेकंड परिशुद्धता के साथ वापस किया गया था। OpenJDK में स्रोत कोड नहीं बदला है, इसलिए मुझे नहीं पता कि बेहतर व्यवहार का क्या कारण है।


डेविड होम्स ऑफ सन ने कुछ साल पहले एक ब्लॉग लेख पोस्ट किया था जिसमें जावा टाइमिंग एपीआई (विशेषकर System.currentTimeMillis()और) पर बहुत विस्तृत नज़र हैSystem.nanoTime() ) , जब आप किसका उपयोग करना चाहते हैं, और वे आंतरिक रूप से कैसे काम करेंगे।

हॉटस्पॉट वीएम के अंदर: घड़ियां, टाइमर और शेड्यूलिंग इवेंट - भाग I - विंडोज

जावा के लिए विंडोज पर एपीआई के लिए इस्तेमाल होने वाले टाइमर का एक बहुत ही दिलचस्प पहलू जो एक समयबद्ध प्रतीक्षा पैरामीटर है, यह है कि टाइमर का रिज़ॉल्यूशन इस आधार पर बदल सकता है कि अन्य एपीआई कॉल क्या हो सकते हैं - सिस्टम वाइड (विशेष प्रक्रिया में ही नहीं) । वह एक उदाहरण दिखाता है जहां उपयोग करने Thread.sleep()से यह रिज़ॉल्यूशन परिवर्तन होगा।


1
@Arkadiy: क्या आपके पास अपडेट के लिए स्टेटमेंट है?
Lii

@ एलआईआई - दुर्भाग्य से, नहीं। यह इस प्रश्न में कोड को चलाने से आता है: stackoverflow.com/questions/34090914/… । कोड जावा 7 के साथ 15ms परिशुद्धता और जावा 8 के साथ 1 एमएस परिशुद्धता का उत्पादन करता है

2
मैं currentTimeMillis पता लगाया करने के लिए ओएस :: javaTimeMillis में हॉटस्पॉट / src / ओएस / विंडोज़ / VM / OpenJDK में os_windows.cpp ( hg.openjdk.java.net/jdk8/jdk8/hotspot/file/87ee5ee27509/src/os/... ) । ऐसा लगता है कि यह अभी भी गेटसिस्टमटाइमएस्फाइलटाइम है, इसलिए मुझे नहीं पता कि बदलाव कहां से आता है। या अगर यह मान्य है। उपयोग करने से पहले परीक्षण करें।

व्यवहार में परिवर्तन GetSystemTimeAsFileTimeXP बनाम 7 में काम करने के तरीके को बदलने का परिणाम है अधिक विवरण के लिए यहां देखें (tl; ड्रॉ इसे और अधिक सटीक मिला क्योंकि संपूर्ण सिस्टम ने कुछ और सटीक समय विधियों को पेश किया)।

11

System.nanoTime()पुराने JVMs में समर्थित नहीं है। यदि वह चिंता का विषय है, तो साथ रहेंcurrentTimeMillis

सटीकता के बारे में, आप लगभग सही हैं। कुछ विंडोज मशीनों पर, currentTimeMillis()लगभग 10ms (50ms नहीं) का एक संकल्प है। मुझे यकीन नहीं है कि क्यों, लेकिन कुछ विंडोज मशीनें लिनक्स मशीनों की तरह ही सटीक हैं।

मैंने पूर्व में मध्यम सफलता के साथ GAGETimer का उपयोग किया है ।


3
"पुराने जेवीएम" कौन से हैं? जावा 1.2 या कुछ और?
साइमन फोर्सबर्ग

1
System.nanoTime () को 2004 में Java 1.5 में पेश किया गया था। 2013 में Java 1.4 ने समर्थन बढ़ाया, इसलिए यह कहना बहुत सुरक्षित है कि System.nanoTime () अब इस पर भरोसा किया जा सकता है और यह उत्तर अब पुराना है।
डेव एल।

9

जैसा कि दूसरों ने कहा है, currentTimeMillis घड़ी का समय है, जो दिन के समय की बचत के समय के कारण बदलता है, उपयोगकर्ता समय सेटिंग, लीप सेकंड और इंटरनेट टाइम सिंक को बदलते हैं। यदि आपका ऐप नीरस समय मूल्यों को बढ़ाने पर निर्भर करता है, तो आप इसके बजाय नैनो टाइम पसंद कर सकते हैं।

आप सोच सकते हैं कि खिलाड़ी खेल खेलने के दौरान समय सेटिंग्स के साथ फ़िदा नहीं होंगे, और शायद आप सही होंगे। लेकिन इंटरनेट टाइम सिंक, या शायद दूरस्थ डेस्कटॉप उपयोगकर्ताओं के कारण व्यवधान को कम मत समझना। नैनो टाइम एपीआई इस तरह के व्यवधान के लिए प्रतिरक्षा है।

यदि आप घड़ी के समय का उपयोग करना चाहते हैं, लेकिन इंटरनेट टाइम सिंक के कारण बंद होने से बचते हैं, तो आप एनटीपी क्लाइंट जैसे कि मेइनबर्ग पर विचार कर सकते हैं, जो घड़ी को समय-समय पर रीसेट करने के बजाय घड़ी की दर को शून्य कर देता है।

मेरा अपना व्यक्तिगत अनुभव ही बयां होता है। एक मौसम अनुप्रयोग में जो मैंने विकसित किया था, मैं बेतरतीब ढंग से हवा की गति वाले स्पाइक्स प्राप्त कर रहा था। मुझे यह महसूस करने में थोड़ा समय लगा कि एक विशिष्ट पीसी पर घड़ी के समय के व्यवहार से मेरा टाइमबेस बाधित हो रहा था। मेरी सभी समस्याएं गायब हो गईं जब मैंने नैनो टाइम का उपयोग करना शुरू किया। कच्ची शुद्धता या पूर्ण सटीकता की तुलना में मेरे आवेदन के लिए संगति (एकरूपता) अधिक महत्वपूर्ण थी।


19
"currentTimeMillis घड़ी का समय है, जो दिन के समय की बचत के कारण बदल जाता है" ... बहुत यकीन है कि यह कथन गलत है। System.currentTimeMillis()यूनिक्स / पॉज़िक्स युग के बाद की रिपोर्ट (मिलीसेकंड में) बीत गई जो मध्यरात्रि, 1 जनवरी, 1970 यूटीसी है। क्योंकि UTC को डेलाइट बचत के लिए कभी समायोजित नहीं किया जाता है, यह मान तब ऑफ़सेट नहीं होगा जब स्थानीय समय ज़ोन दिन के उजाले की बचत के लिए स्थानीय समय को जोड़ते हैं या विषय को जोड़ते हैं। इसके अलावा, जावा टाइम स्केल लीप सेकंड को सुचारू करता है ताकि दिन में 86,400 सेकंड दिखाई दें।
स्काउट

5

हां, यदि इस तरह के सटीक उपयोग की आवश्यकता है System.nanoTime() , लेकिन ध्यान रखें कि आपको तब जावा 5+ जेवीएम की आवश्यकता होती है।

मेरे XP सिस्टम पर, मुझे निम्न कोड का उपयोग करते हुए कम से कम 100 माइक्रोसेकंड 278 नैनोसेकंड की सूचना प्रणाली समय दिखाई देता है :

private void test() {
    System.out.println("currentTimeMillis: "+System.currentTimeMillis());
    System.out.println("nanoTime         : "+System.nanoTime());
    System.out.println();

    testNano(false);                                                            // to sync with currentTimeMillis() timer tick
    for(int xa=0; xa<10; xa++) {
        testNano(true);
        }
    }

private void testNano(boolean shw) {
    long strMS=System.currentTimeMillis();
    long strNS=System.nanoTime();
    long curMS;
    while((curMS=System.currentTimeMillis()) == strMS) {
        if(shw) { System.out.println("Nano: "+(System.nanoTime()-strNS)); }
        }
    if(shw) { System.out.println("Nano: "+(System.nanoTime()-strNS)+", Milli: "+(curMS-strMS)); }
    }

4

गेम ग्राफिक्स और चिकनी स्थिति अपडेट के लिए, System.nanoTime()बजाय उपयोग करेंSystem.currentTimeMillis() । मैंने एक गेम में currentTimeMillis () से नैनो टाइम () में स्विच किया और गति की चिकनाई में एक प्रमुख दृश्य सुधार प्राप्त किया।

हालांकि एक मिलीसेकंड ऐसा लग सकता है जैसे कि यह पहले से ही सटीक होना चाहिए, नेत्रहीन यह नहीं है। कारकों में nanoTime()सुधार कर सकते हैं शामिल हैं:

  • दीवार-घड़ी रिज़ॉल्यूशन के नीचे सटीक पिक्सेल स्थिति
  • पिक्सेल के बीच विरोधी उर्फ ​​की क्षमता, यदि आप चाहते हैं
  • विंडोज दीवार-घड़ी की अशुद्धि
  • घड़ी घबराना (जब दीवार घड़ी वास्तव में आगे टिकती है तो असंगति)

जैसा कि अन्य उत्तर बताते हैं, नैनोटाइम की एक प्रदर्शन लागत होती है यदि बार-बार कहा जाता है - इसे प्रति फ्रेम केवल एक बार कॉल करना सबसे अच्छा होगा, और पूरे फ्रेम की गणना करने के लिए समान मूल्य का उपयोग करें।


1

मुझे नैनोटाइम के साथ अच्छा अनुभव रहा है । यह JNI लाइब्रेरी का उपयोग करते हुए दो सेकंड (उस दूसरे के भीतर के नैनोसेकंड के बाद से सेकंड) के रूप में दीवार-घड़ी का समय प्रदान करता है। यह JNI भाग के साथ उपलब्ध है जो विंडोज और लिनक्स दोनों के लिए पूर्वनिर्धारित है।


1

System.currentTimeMillis()बीते हुए समय के लिए सुरक्षित नहीं है क्योंकि यह विधि सिस्टम के सिस्टम के रीयलटाइम घड़ी परिवर्तनों के प्रति संवेदनशील है। आपको उपयोग करना चाहिएSystem.nanoTime । कृपया जावा सिस्टम सहायता देखें:

नैनो टाइम विधि के बारे में:

.. यह विधि नैनोसेकंड सटीक प्रदान करती है, लेकिन जरूरी नहीं कि नैनोसेकंड रिज़ॉल्यूशन (अर्थात, कितनी बार मूल्य परिवर्तन हो) - कोई गारंटी नहीं दी जाती है सिवाय इसके कि रिज़ॉल्यूशन कम से कम उतना ही अच्छा है जितना कि currentTimeMillis () ।।

यदि आप System.currentTimeMillis()अपने बीते हुए समय का उपयोग नकारात्मक कर सकते हैं (वापस <- भविष्य के लिए)


-3

एक बात यहाँ नैनो टाइम विधि की विसंगति है। यह एक ही इनपुट के लिए बहुत सुसंगत मूल्य नहीं देता है। समांतर टाइममिलिस प्रदर्शन और स्थिरता के मामले में बहुत बेहतर करता है, और यह भी, हालांकि नैनोटाइम के रूप में सटीक नहीं है, त्रुटि का एक कम मार्जिन है। , और इसलिए इसके मूल्य में अधिक सटीकता। इसलिए मेरा सुझाव है कि आप currentTimeMillis का उपयोग करें


6
जैसा कि अन्य उत्तरों और टिप्पणियों में उल्लेख किया गया है, currentTimeMillis सिस्टम क्लॉक में परिवर्तन के अधीन है और इसलिए JVM में कुछ पहले की घटना के बाद बीता हुआ समय की गणना के लिए एक खराब विकल्प है।
द्वंद्वयुद्ध मार्करों
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.