كيفية الحصول على الطابع الزمني من القراد الدقة في .NET / C# ؟

StackOverflow https://stackoverflow.com/questions/1416139

  •  06-07-2019
  •  | 
  •  

سؤال

حتى الآن أنا استخدامها DateTime.Now للحصول على الطوابع الزمنية ، ولكن إذا لاحظت أن طباعة DateTime.Now في حلقة سوف ترى أن الزيادات في descrete يقفز تقريبا.15 مللي.ولكن لبعض السيناريوهات في طلبي أنا بحاجة للحصول على أدق زمني ممكن ، ويفضل أن يكون ذلك مع وضع علامة (=100 نانو ثانية) الدقة.أي أفكار ؟

تحديث:

على ما يبدو ، StopWatch / QueryPerformanceCounter هو الطريق للذهاب ، ولكن يمكن فقط أن تستخدم في قياس الوقت, لذلك كان التفكير في الدعوة DateTime.Now عند بدء تشغيل التطبيق ثم فقط StopWatch تشغيل ثم فقط إضافة الوقت المنقضي من StopWatch أن القيمة الأولية عاد من DateTime.Now.على الأقل يجب أن تعطيني دقيقة النسبية الطوابع, صحيح ؟ ما رأيك بهذا (الاختراق)?

ملاحظة:

StopWatch.ElapsedTicks يختلف StopWatch.Elapsed.Ticks!اعتدت في السابق على افتراض 1 القراد = 100 نانوثانية ، ولكن في هذه الحالة 1 القراد = 1 / StopWatch.Frequency.لذلك للحصول على القراد يعادل استخدام التاريخ والوقت StopWatch.Elapsed.Ticks.لقد تعلمت هذا الطريق الصعب.

ملاحظة 2:

باستخدام ساعة توقيت نهج لاحظت يحصل متزامنة مع الوقت الحقيقي.بعد حوالي 10 ساعات ، كان قبل 5 ثوان.لذا أعتقد أن على المرء أن تتم إعادة مزامنة كل X أو نحو ذلك حيث X يمكن أن يكون 1 ساعة, 30 دقيقة, 15 دقيقة, الخ.أنا لست متأكدا ما المثلى زمنية من أجل resyncing أن كل المزامنة سوف تغير الإزاحة التي يمكن أن تصل إلى 20 مللي.

هل كانت مفيدة؟

المحلول

قيمة ساعة النظام أن DateTime.Now يقرأ هو فقط تحديث كل 15 مللي ثانية أو نحو ذلك (أو 10 ms على بعض الأنظمة) ، وهذا هو السبب في الأوقات الكم حول تلك الفترات.هناك إضافية تكميم التأثير الذي ينتج عن حقيقة أن التعليمات البرمجية الخاصة بك قيد التشغيل في مؤشرات التشغيل ، وبالتالي هناك مساحات حيث التطبيق الخاص بك لا "على قيد الحياة" ومن ثم لا قياس حقيقية في الوقت الحالي.

منذ كنت تبحث عن فرصة فائقة الدقة ختم الوقت قيمة (بدلا من مجرد توقيت التعسفي المدة) ، Stopwatch فئة في حد ذاته لا ما تحتاج.أعتقد أن عليك أن تفعل ذلك بنفسك مع نوع من DateTime/Stopwatch الهجين.عند تشغيل التطبيق ، يمكنك تخزين الحالي DateTime.UtcNow القيمة (أيالنفط الخام-القرار الوقت عندما يبدأ تطبيق) ثم أيضا بدء Stopwatch كائن مثل هذا:

DateTime _starttime = DateTime.UtcNow;
Stopwatch _stopwatch = Stopwatch.StartNew();

ثم كلما كنت في حاجة عالية الدقة DateTime قيمة سوف تحصل على مثل هذا:

DateTime highresDT = _starttime.AddTicks(_stopwatch.Elapsed.Ticks);

قد تحتاج أيضا إلى دوري تعيين _starttime و _stopwatch ، للحفاظ على الوقت الناتجة من الحصول على بعيدا جدا متزامنة مع نظام الوقت (على الرغم من أنني لست متأكدا من أن هذا يمكن أن يحدث في الواقع و سوف يستغرق وقت طويل أن يحدث على أي حال).

التحديث:إذ يبدو أن ساعة توقيت لا الخروج من المزامنة مع نظام الوقت (بمقدار نصف ثانية لكل ساعة) ، أعتقد أنه من المنطقي أن تعيين الهجين DateTime الدرجة على أساس مقدار الوقت الذي يمر بين المكالمات للتحقق من الوقت:

public class HiResDateTime
{
    private static DateTime _startTime;
    private static Stopwatch _stopWatch = null;
    private static TimeSpan _maxIdle = 
        TimeSpan.FromSeconds(10);

    public static DateTime UtcNow
    {
        get
        {
            if ((_stopWatch == null) || 
                (_startTime.Add(_maxIdle) < DateTime.UtcNow))
            {
                Reset();
            }
            return _startTime.AddTicks(_stopWatch.Elapsed.Ticks);
        }
    }

    private static void Reset()
    {
        _startTime = DateTime.UtcNow;
        _stopWatch = Stopwatch.StartNew();
    }
}

إذا قمت بإعادة تعيين الهجين الموقت في بعض فترات منتظمة (مثلا كل ساعة أو شيء) ، كنت عرضة لخطر من ضبط الوقت مرة أخرى قبل قراءة آخر الوقت ، وكأنه نوع من مصغرة التوقيت الصيفي المشكلة.

نصائح أخرى

للحصول على دقة عالية القراد-عد الرجاء استخدام ساعة توقيت ثابت.GetTimestamp()-الطريقة:

long tickCount = System.Diagnostics.Stopwatch.GetTimestamp();
DateTime highResDateTime = new DateTime(tickCount);

مجرد إلقاء نظرة على .صافي البرمجية المصدر:

    public static long GetTimestamp() {
        if(IsHighResolution) {
            long timestamp = 0;    
            SafeNativeMethods.QueryPerformanceCounter(out timestamp);
            return timestamp;
        }
        else {
            return DateTime.UtcNow.Ticks;
        }   
    }

المصدر هنا: http://referencesource.microsoft.com/#System/services/monitoring/system/diagnosticts/Stopwatch.cs,69c6c3137e12dab4

[الجواب المقبول لا يبدو أن الموضوع آمنة ، باعترافها يمكن أن تذهب إلى الوراء في الوقت المناسب مما تسبب في تكرار الطوابع ، وبالتالي هذا البديل الإجابة]

إذا ما كنت تهتم حقا حول (في تعليق) هو في الواقع فريدة من نوعها الزمني التي تم تخصيصها في الصارم ترتيب تصاعدي وهو ما يقابل قدر الإمكان أن النظام الوقت يمكنك أن تجرب هذا النهج البديل:

public class HiResDateTime
{
   private static long lastTimeStamp = DateTime.UtcNow.Ticks;
   public static long UtcNowTicks
   {
       get
       {
           long orig, newval;
           do
           {
               orig = lastTimeStamp;
               long now = DateTime.UtcNow.Ticks;
               newval = Math.Max(now, orig + 1);
           } while (Interlocked.CompareExchange
                        (ref lastTimeStamp, newval, orig) != orig);

           return newval;
       }
   }
}

هذه الاقتراحات كلها تبدو من الصعب جدا!إذا كنت على ويندوز 8 أو Server 2012 أو أعلى ، استخدام GetSystemTimePreciseAsFileTime على النحو التالي:

[DllImport("Kernel32.dll", CallingConvention = CallingConvention.Winapi)]
static extern void GetSystemTimePreciseAsFileTime(out long filetime);

public DateTimeOffset GetNow()
{
    long fileTime;
    GetSystemTimePreciseAsFileTime(out fileTime);
    return DateTimeOffset.FromFileTime(fileTime);
}

هذا أفضل بكثير من الدقة DateTime.Now من دون أي جهد.

راجع MSDN للحصول على مزيد من المعلومات: http://msdn.microsoft.com/en-us/library/windows/desktop/hh706895(v=مقابل 85).aspx

أنه لا عودة الأكثر دقة التاريخ والوقت من المعروف أن نظام التشغيل.

نظام التشغيل كما يوفر دقة أعلى توقيت خلال QueryPerformanceCounter و QueryPerformanceFrequency (.صافي Stopwatch الطبقة).هذه تمكنك من الوقت فاصل ولكن لا تعطيك التاريخ والوقت من اليوم.هل يمكن القول أن هذه سوف تكون قادرة على إعطائك دقيقة جدا في الوقت و اليوم ، ولكن لست متأكدا كيف سيئة فإنها تحرف على مدى فترة طويلة.

1).إذا كنت بحاجة إلى قرار عالية الدقة المطلقة:لا يمكنك استخدام DateTime.Now عندما يستند على الساعة 15 ms الفاصل (إلا إذا كان هو ممكن "الشريحة" المرحلة).

بدلا من مصدر خارجي من أفضل قرار المطلق دقة الوقت (مثلا ، ntp) ، t1 أدناه, يمكن أن تكون جنبا إلى جنب مع ارتفاع قرار توقيت (ساعة التوقيت / QueryPerformanceCounter).


2).إذا كنت بحاجة فقط عالية الدقة:

عينة DateTime.Now (t1) مرة واحدة جنبا إلى جنب مع قيمة من عالية الدقة جهاز توقيت (ساعة التوقيت / QueryPerformanceCounter) (tt0).

إذا كانت القيمة الحالية من ارتفاع القرار الموقت tt ثم الوقت الحالي ، t, هو:

t = t1 + (tt - tt0)

3).بديل يمكن أن نفصل مطلق الوقت ، ترتيب الأحداث المالية:قيمة واحدة المطلق الوقت (15 ms القرار ، وربما قبالة عن طريق عدة دقائق) واحد قيمة الطلب (على سبيل المثال ، تزايد قيمة كل الوقت و متجر).بدء قيمة يمكن استنادا إلى نظام القيمة العالمية أو تكون مشتقة من مطلق الوقت عند بدء تشغيل التطبيق.

هذا الحل سيكون أكثر قوة كما أنها لا تعتمد على الأجهزة الأساسية تنفيذ الساعات/توقيت (قد تختلف الوسطاء systems).

هذا هو الكثير من العمل من أجل شيء بسيط جدا.مجرد إدراج التاريخ والوقت في قاعدة البيانات الخاصة بك مع التجارة.ثم الحصول على التجارة من أجل استخدام عمود الهوية التي ينبغي أن يكون تزايد قيمة.

إذا كنت إدخالها في قواعد بيانات متعددة و محاولة التوفيق بين بعد وقوعها ثم سوف يكون سوء حساب النظام التجاري بسبب أي تباين طفيف في قاعدة البيانات الخاصة بك مرة (حتى ns الزيادات كما قلت)

لحل قاعدة بيانات متعددة المسألة قد تعرض خدمة واحدة أن كل التجارة يضرب للحصول على النظام.الخدمة يمكن إرجاع التاريخ والوقت.UtcNow.القراد و تزايد التجارة رقم.

حتى باستخدام أحد الحلول أعلاه أي شخص إجراء الصفقات من موقع على الشبكة مع أكثر من الكمون يمكن أن مكان الحرف الأول (العالم الحقيقي) ، ولكنها دخلت في أمر خاطئ بسبب الكمون.لأن هذه التجارة يجب النظر في وضعها في قاعدة البيانات ، ليس على المستخدمين لوحات المفاتيح.

15 مللي ثانية (في الواقع يمكن أن يكون 15-25 ms) دقة يستند إلى نظام التشغيل Windows 55 هرتز/65 هرتز توقيت القرار.وهذا هو أيضا الأساسي TimeSlice الفترة.المتضررة يقوم نظام ويندوز.أشكال.توقيت, خيوط.الخيط.النوم, خيوط.توقيت, ، وما إلى ذلك.

للحصول على دقة فترات يجب عليك استخدام ساعة توقيت الدرجة.فإنه سيتم استخدام عالية الدقة إذا كانت متوفرة.جرب ما يلي البيانات لمعرفة:

Console.WriteLine("H = {0}", System.Diagnostics.Stopwatch.IsHighResolution);
Console.WriteLine("F = {0}", System.Diagnostics.Stopwatch.Frequency);
Console.WriteLine("R = {0}", 1.0 /System.Diagnostics.Stopwatch.Frequency);

أحصل على R=6E-08 ثانية أو 60 نانوثانية.فإنه ينبغي أن يكون كافيا لهذا الغرض الخاص.

أود إضافة ما يلي فيما يتعلق MusiGenesis الجواب إعادة مزامنة التوقيت.

المعنى:ما الوقت يجب أن تستخدم لإعادة مزامنة ( إن _maxIdle في MusiGenesis الإجابة)

هل تعلم أن مع هذا الحل الذي ليست دقيقة تماما ، thats لماذا إعادة المزامنة.ولكن أيضا ما ضمنا نريد نفس الشيء إيان بزاز الحل:

فريدة من نوعها الزمني التي تم تخصيصها في الصارم ترتيب تصاعدي

ولذلك مقدار الوقت بين اثنين إعادة المزامنة ( _maxIdle يتيح نسميها SyncTime) يجب أن تكون وظيفة من 4 أشياء:

  • على DateTime.UtcNow القرار
  • نسبة دقة تريد
  • الدقة المستوى الذي تريده
  • تقدير خارج المزامنة نسبة من الجهاز الخاص بك

ومن الواضح أن القيد الأول على هذا المتغير ليكون :

خارج المزامنة نسبة <= نسبة دقة

على سبيل المثال :وأنا لا أريد بلدي دقة أن تكون أسوأ من 0.5 s/ساعة أو 1 مللي ثانية/يوم الخ...(في اللغة الإنجليزية السيئة:أنا لا أريد أن يكون أكثر خطأ من 0.5 s/ساعة=12s/يوم).

بحيث لا يمكن تحقيق دقة أفضل مما ساعة توقيت نقدم لكم على الكمبيوتر الخاص بك.ذلك يعتمد على من مزامنة النسبة التي قد لا تكون ثابتة.

عائق آخر هو الحد الأدنى من الوقت بين اثنين المزامنة:

Synctime >= DateTime.UtcNow القرار

هنا دقة ترتبط لأنه إذا كنت تستخدم دقة عالية (على سبيل المثال لتخزين في DB) ولكن أقل دقة ، قد كسر إيان بزاز البيان هذا هو الصارم ترتيب تصاعدي.

ملاحظة: يبدو التاريخ والوقت.UtcNow قد يكون أكبر الافتراضي Res من 15ms (1ms على الجهاز الخاص بي) اتبع الرابط:دقة عالية التاريخ والوقت.UtcNow

دعونا نأخذ مثالا على ذلك:

تخيل خارج المزامنة نسبة علق أعلاه.

بعد حوالي 10 ساعات ، كان قبل 5 ثوان.

أقول أريد microsec الدقة.بلدي الموقت res هو 1ms (انظر أعلاه ملاحظة)

حتى نقطة نقطة:

  • على DateTime.UtcNow القرار : 1ms
  • دقة نسبة >= out-of-sync النسبة ، دعونا نلقي الأكثر دقة ممكنة لذلك : دقة نسبة = out-of-sync نسبة
  • الدقة المستوى الذي تريده : 1 microsec
  • تقدير خارج المزامنة نسبة من الجهاز الخاص بك : 0.5 s/ساعة (وهذا هو أيضا بلدي دقة)

إذا قمت بإعادة تعيين كل 10s, تخيل في 9.999 s ، 1ms قبل إعادة تعيين.هنا يمكنك إجراء مكالمة خلال هذه الفترة.الوقت الخاص بك وظيفة المؤامرة قبل :0.5/3600*9.999 s eq 1.39 ms.يمكنك عرض الوقت 10.000390 ثانية.بعد UtcNow القراد ، إذا قمت بإجراء مكالمة داخل 390micro ثانية ، سيكون لديك عدد أقل شأنا من سابقتها.أسوأ إذا كان هذا خارج المزامنة نسبة عشوائية اعتمادا على تحميل وحدة المعالجة المركزية أو غيرها من الأمور.

الآن دعونا نقول أنا وضعت SyncTime في قيمة الحد الأدنى > أنا المزامنة كل 1ms

تفعل نفس التفكير من شأنه أن يضع لي في وقت مبكر من 0.139 microsec < أقل شأنا من الدقة أريد.لذلك إذا كنت استدعاء الدالة في 9.999 ms, حتى 1microsec قبل إعادة تعيين سوف مؤامرة 9.999.و بعد مؤامرة 10.000.سوف يكون أمر جيد.

حتى هنا في غيرها من القيد هو :دقة-نسبة × SyncTime < مستوى الدقة ، دعونا نقول أن تتأكد لأن عدد يمكن تقريب ذلك دقة-نسبة × SyncTime < مستوى الدقة/2 هو جيد.

تم حل المشكلة.

لذا خلاصة سريعة ليكون :

  • استرداد توقيت القرار.
  • حساب تقدير خارج المزامنة نسبة.
  • دقة نسبة >= out-of-sync نسبة تقدير ، أفضل دقة = out-of-sync نسبة
  • اختيار مستوى الدقة النظر التالية:
  • توقيت القرار <= SyncTime <= PrecisionLevel/(2*دقة-نسبة)
  • أفضل دقة يمكنك تحقيق هو توقيت القرار*2*خارج المزامنة نسبة

أعلاه نسبة (0.5/hr) الصحيح SyncTime سيكون 3.6 ms, لذا تقريب إلى 3ms.

مع النسبة المذكورة و توقيت القرار من 1ms.إذا كنت ترغب في واحد علامة الدقة المستوى (0.1 microsec), كنت بحاجة إلى خارج المزامنة نسبة لا يزيد عن : 180ms/ساعة.

في آخر الإجابة على الإجابة الخاصة به MusiGenesis الدولة:

@هيرمان:لقد تم تشغيل اختبار مماثل لمدة ساعتين (من دون إعادة تصحيح) ، ساعة توقيت على أساس مؤقت فقط تشغيل حوالي 400 ms المقبلة بعد 2 ساعات, لذلك الانحراف نفسه يبدو أن متغير (ولكن لا يزال شديد جدا).أنا متفاجئ جدا أن تحرف هذه سيئة ؛ أعتقد أن هذا هو السبب في ساعة توقيت في النظام.تشخيص.– MusiGenesis

حتى ساعة توقيت بدقة قريبة من 200ms/ساعة, تقريبا لدينا 180ms/ساعة.هل هناك أي رابط لماذا الرقم وهذا الرقم قريب جدا ؟ لا أعرف.ولكن هذه الدقة بما فيه الكفاية بالنسبة لنا لتحقيق القراد الدقة

أفضل PrecisionLevel:على سبيل المثال أعلاه ، 0.27 microsec.

ولكن ماذا يحدث إذا اتصلت عدة مرات بين 9.999 ms و إعادة المزامنة.

2 يدعو إلى وظيفة يمكن في نهاية المطاف مع نفس الطابع الزمني يتم إرجاعها الوقت سيكون 9.999 على حد سواء (كما أنا لا أرى أكثر دقة).للتحايل على هذا, لا يمكنك لمس مستوى الدقة لأنه مرتبط SyncTime قبل العلاقة المذكورة أعلاه.لذلك يجب أن تنفذ إيان بزاز الحل هو على تلك الحالة.

من فضلك لا تتردد في التعليق جوابي.

إذا تحتاج الزمني لتنفيذ معايير استخدام ساعة توقيت وهو أفضل بكثير من الدقة من التاريخ والوقت.الآن.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top