2009-10-13 18 views
24

Kolega i ja poruszamy się w tej sprawie i mam nadzieję uzyskać opinie zewnętrzne na temat tego, czy moje proponowane rozwiązanie jest dobrym pomysłem, czy nie.Optymalizowanie alternatywy dla DateTime.Now

Po pierwsze, zrzeczenie się: zdaję sobie sprawę, że pojęcie "optymalizacji DateTime.Now" dla niektórych z was jest szalone. Mam parę obrony poboru:

  1. Czasami podejrzewam, że ci ludzie, którzy zawsze mówią: „Komputery są szybkie, czytelność zawsze przychodzi przed optymalizacją” są często mówiąc z doświadczenia tworzenia aplikacji gdzie wydajność, choć może to być ważne, nie jest krytyczne. Mówię o tym, że rzeczy muszą się wydarzyć tak blisko, jak to tylko możliwe - w ciągu nanosekund (w niektórych branżach ta sprawa dotyczy np. Handlu w czasie rzeczywistym z wysoką częstotliwością).
  2. Mając to na uwadze, alternatywne podejście, które opisuję poniżej, jest w rzeczywistości dość czytelne. To nie jest dziwaczny hack, tylko prosta metoda, która działa niezawodnie i szybko.
  3. Mamy mają prowadzi testy. DateTime.Nowis slow (relatywnie rzecz biorąc). Metoda poniżej jest szybsza o.

Teraz, na samo pytanie.

Zasadniczo z testów odkryliśmy, że uruchomienie DateTime.Now zajmuje około 25 tików (około 2,5 mikrosekundy). Jest to średnio uśrednione na tysiące do milionów połączeń. Wygląda na to, że pierwsze połączenie zajmuje naprawdę dużo czasu, a kolejne połączenia są znacznie szybsze. Ale nadal 25 kleszczy jest średnią.

Jednakże, mój współpracownik i ja zauważyliśmy, że DateTime.UtcNow zajmuje znacznie mniej czasu do uruchomienia - średnio zaledwie 0,03 mikrosekundy.

Biorąc pod uwagę, że nasza aplikacja nie będzie działać, gdy nastąpiła zmiana w czas letni, moja sugestia było stworzenie następujące klasy:

public static class FastDateTime { 
    public static TimeSpan LocalUtcOffset { get; private set; } 

    public static DateTime Now { 
     get { return DateTime.UtcNow + LocalUtcOffset; } 
    } 

    static FastDateTime() { 
     LocalUtcOffset = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now); 
    } 
} 

Innymi słowy, określić przesunięcie UTC dla lokalna strefa czasowa raz - przy starcie - i od tego momentu wykorzystaj prędkość DateTime.UtcNow, aby uzyskać bieżący czas o wiele szybciej poprzez FastDateTime.Now.

Mogłem zobaczyć, że jest to problem, jeśli przesunięcie UTC uległo zmianie w czasie działania aplikacji (jeśli na przykład aplikacja działała przez noc); ale jak już wspomniałem, w naszej sprawie tak się nie stanie.

Mój kolega ma inny pomysł na temat tego, jak to zrobić, co jest nieco zbyt zaangażowane, aby mi to wyjaśnić. Ostatecznie, o ile mogę powiedzieć, oba nasze podejścia zwracają dokładny wynik, mój jest nieco szybszy (~ 0.07 mikrosekund vs. ~ 0.21 mikrosekund).

Co chcę wiedzieć:

  1. Am I brakuje czegoś tutaj? Biorąc pod uwagę powyższy fakt, że aplikacja będzie działała tylko w ramach czasowych jednej daty, czy jest ona bezpieczna?
  2. Czy ktoś inny może pomyśleć o nawet szybszym sposobie uzyskania aktualnego czasu?
+2

Przejście DST jest zwykłym niedopatrzymaniem przy wprowadzaniu tego typu uproszczeń, a już wcześniej zastrzegłeś, że to nie będzie problemem. Łapie ludzi na baczność, aby odkryć, że oni (i ich oprogramowanie użytkowe) żyją w 2 strefach czasowych, bez przesuwania się o cal. I jest to podwójnie trudne, że jedyny moment, w którym twój pakiet testowy go przechwytuje, jest taki, że zdarza się, że działa podczas przejścia DST, co jest rzadkim zjawiskiem w najlepszym przypadku (lub jest wyśmiewany w ramach zestawu testów, który, jak twierdzę, jest równomierny rzadsze rzeczy). – PaulMcG

Odpowiedz

26

Czy można po prostu użyć DateTime.UtcNow, i tylko przekonwertować na czas lokalny, gdy dane są prezentowane? Zdecydowałeś już, że DateTime.UtcNow jest znacznie szybszy i usunie wszelkie niejasności wokół DST.

+2

+1 Czytałem, że UtcNow jest dużo szybszy, co było dla mnie zaskakujące. http://blogs.msdn.com/clrperfblog/archive/2009/09/08/computing-time-in-net.aspx – kenny

+2

Zamierzam iść dalej i zaakceptować tę odpowiedź, ponieważ ma tak wiele cholernego sensu. Niestety nie sądzę, że będziemy to robić (przynajmniej jeszcze nie) z powodu ilości kodu, który musielibyśmy zmienić. Ale jest to niewiarygodnie logiczna sugestia. –

+0

Ważna jest prezentacja: nie ma jednego czasu lokalnego, więc można go obliczyć tylko wtedy, gdy jest prezentowany. –

2

Aby odpowiedzieć w odwrotnej kolejności:

2) Nie mogę myśleć o szybszy sposób.

1) Warto byłoby sprawdzenie, czy istnieją jakiekolwiek ulepszenia ram w rurociągu jak mają just announced for System.IO

Trudno być pewni o bezpieczeństwo, ale jest to coś, co woła za dużo testów jednostkowych. Uwagę przykuwa światło dzienne. Systemowy jest oczywiście bardzo zahartowany w walce, a twój nie.

7

Jedną z różnic między wynikiem

DateTime.Now 

i

DateTime.UtcNow + LocalUtcOffset 

jest wartość obiektu - Lokalna vs Utc odpowiednio. Jeśli wynikowa wartość DateTime jest przekazywana do innej biblioteki, rozważ zwrot w postaci:

DateTime.SpecifyKind(DateTime.UtcNow + LocalUtcOffset, DateTimeKind.Local) 
4

Podoba mi się Twoje rozwiązanie. Zrobiłem kilka testów, aby zobaczyć, jak dużo szybciej jest ona w porównaniu do zwykłej DateTime.Now

DateTime.UtcNow jest 117 razy szybciej niż DateTime.Now

wykorzystaniem DateTime.UtcNow jest wystarczająco dobre, jeśli jesteśmy zainteresowani tylko w czasie trwania, a nie sam czas. Jeśli potrzebujemy jedynie obliczyć czas trwania określonej sekcji kodu (wykonując duration= End_time - Start_time), strefa czasowa nie jest ważna i wystarczy DateTime.UtcNow.

Ale jeśli potrzebujemy czasu sam to musimy zrobić DateTime.UtcNow + LocalUtcOffset

Wystarczy dodanie przedział czasowy spowalnia trochę i teraz według moich testów mamy tylko 49 razy szybciej niż regularne DateTime.Now

Jeśli umieścimy to obliczenie w oddzielnej funkcji/klasie zgodnie z sugestią, wywołanie metody spowolni nas jeszcze bardziej , a my tylko 34 razy szybciej.

Ale nawet 34 razy szybciej jest dużo !!!

W skrócie, Korzystanie DateTime.UtcNow jest znacznie szybsze niż DateTime.Now

Jedynym sposobem, stwierdzono poprawę sugerowana klasa jest użycie kodu inline: DateTime.UtcNow + LocalUtcOffset zamiast wywoływania metody klasy

BTW próbuje zmusić kompilator do kompilacji jako wbudowany przy użyciu [MethodImpl(MethodImplOptions.AggressiveInlining)] nie wydaje się, aby przyspieszyć rzeczy.