2009-10-13 6 views
24

Un collègue et moi allons revenir en arrière sur cette question et je suis l'espoir d'obtenir des opinions en dehors de savoir si ou non ma solution proposée est une bonne idée.Optimisation des alternatives à DateTime.Now

D'abord, une mise en garde: je me rends compte que la notion de « l'optimisation DateTime.Now » semble fou à certains d'entre vous. J'ai deux ou trois défenses préventives:

  1. Je pense parfois que les gens qui disent toujours, « Les ordinateurs sont rapides, la lisibilité toujours vient avant l'optimisation » parlent souvent d'expérience dans le développement d'applications où les performances, bien que il peut être important, n'est pas critique. Je parle de faire en sorte que les choses se passent le plus près possible de l'instant - comme, en quelques nanosecondes (dans certaines industries, cela a une importance - par exemple, le trading haute fréquence en temps réel).
  2. Même dans cet esprit, l'approche alternative que je décris ci-dessous est, en fait, très lisible. Ce n'est pas un bidouillage bizarre, juste une méthode simple qui fonctionne de manière fiable et rapide.
  3. Nous avons exécute des tests. DateTime.Nowest lent (relativement parlant). La méthode ci-dessous est plus rapide.

Maintenant, sur la question elle-même. Fondamentalement, à partir de tests, nous avons constaté que DateTime.Now prend environ 25 mesures (environ 2,5 microsecondes) pour fonctionner. C'est en moyenne sur des milliers à des millions d'appels, bien sûr. Il semble que le premier appel prenne effectivement beaucoup de temps et que les appels subséquents soient beaucoup plus rapides. Mais encore, 25 ticks est la moyenne.

Cependant, mon collègue et moi avons remarqué que DateTime.UtcNow prend beaucoup moins de temps à s'exécuter - en moyenne, à peine 0,03 microsecondes.

Étant donné que notre demande ne sera jamais en cours d'exécution alors qu'il ya un changement de l'heure d'été, ma suggestion était de créer la classe suivante:

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); 
    } 
} 

En d'autres termes, déterminer le décalage horaire UTC pour la fuseau horaire local une fois - au démarrage - et de ce point de tirer parti en avant la vitesse de DateTime.UtcNow pour obtenir l'heure actuelle beaucoup plus rapide via FastDateTime.Now.

Je pouvais voir ce qui est un problème si l'UTC décalage changé pendant le temps de l'application en cours d'exécution a été (si, par exemple, l'application en cours d'exécution a été du jour au lendemain); mais comme je l'ai déjà dit, dans notre cas, cela n'arrivera pas.

Mon collègue a une idée différente sur la façon de le faire, ce qui est un peu trop compliqué pour moi d'expliquer ici. En fin de compte, autant que je peux dire, nos deux approches retournent un résultat précis, le mien étant légèrement plus rapide (~ 0,07 microsecondes contre ~ 0,21 microsecondes).

Ce que je veux savoir est:

  1. Suis-je manque quelque chose ici? Compte tenu du fait mentionné ci-dessus que l'application ne sera exécutée que dans le délai d'une seule date, FastDateTime.Now est-il sûr?
  2. Quelqu'un d'autre peut-être penser à un plus rapide comment obtenir l'heure actuelle?
+2

La transition DST est l'omission habituelle lors de ce type de simplification, et vous avez déjà stipulé que ce ne sera pas un problème. Il surprend les gens à découvrir qu'ils (et leur logiciel d'application) vivent dans 2 fuseaux horaires, sans bouger d'un pouce. Et il est doublement épineux que la seule fois que votre suite de tests attrape ceci est si elle se produit pendant la transition DST, une occurrence rare au mieux (ou est simulée dans le cadre de la suite de tests, que je dirais est un même chose plus rare). – PaulMcG

Répondre

26

Pourriez-vous simplement utiliser DateTime.UtcNow, et convertir uniquement en heure locale lorsque les données sont présentées? Vous avez déjà déterminé que DateTime.UtcNow est beaucoup plus rapide et cela supprimera toute ambiguïté autour de l'heure d'été.

+2

+1 J'ai lu que UtcNow est beaucoup plus rapide, ce qui m'a surpris. http://blogs.msdn.com/clrperfblog/archive/2009/09/08/computing-time-in-net.aspx – kenny

+2

Je vais aller de l'avant et j'accepte cette réponse parce qu'elle fait tellement de sens. Malheureusement, je ne pense pas que nous allons le faire (du moins pas encore) à cause de la quantité de code que nous devrions changer. Mais c'est une suggestion incroyablement logique. –

+0

C'est la présentation qui est importante: il n'y a pas d'heure locale unique, elle ne peut donc être calculée que lorsqu'elle est présentée. –

2

Pour répondre dans l'ordre inverse:

2) Je ne peux pas penser à une façon plus rapide.

1) Il serait utile de vérifier s'il y a des améliorations du cadre dans le pipeline comme ils ont just announced for System.IO

Il est difficile d'être sûr de la sécurité, mais il est quelque chose qui est en train de pleurer pour un grand nombre de tests unitaires. L'heure d'été me vient à l'esprit. Le système est évidemment très combattu pendant que le vôtre n'est pas.

7

Une différence entre le résultat de

DateTime.Now 

et

DateTime.UtcNow + LocalUtcOffset 

est la valeur de la propriété Kind - respectivement local vs Utc. Si la DateTime résultante est passée à une bibliothèque tiers envisager un retour

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

J'aime votre solution. J'ai fait quelques tests pour voir combien plus vite il est comparé à régulière DateTime.Now

DateTime.UtcNow est 117 fois plus rapide que DateTime.Now

utilise DateTime.UtcNow est assez bon si nous ne sommes intéressés que la durée et non pas le temps lui-même. Si tout ce dont nous avons besoin est de calculer la durée d'une section de code spécifique (en faisant duration= End_time - Start_time) alors le fuseau horaire n'est pas important et DateTime.UtcNow est suffisant.

Mais si nous avons besoin du temps lui-même alors nous devons faire DateTime.UtcNow + LocalUtcOffset

Tout en ajoutant l'intervalle de temps ralentit un peu et maintenant selon mes tests que nous sommes seulement 49 fois plus rapide que la DateTime.Now régulière

Si nous mettons ce calcul dans une fonction/classe séparée comme suggéré, l'appel de la méthode nous ralentit encore plus et nous ne sommes que 34 fois plus rapides.

Mais même 34 fois plus vite c'est beaucoup !!!

En bref, L'utilisation DateTime.UtcNow est beaucoup plus rapide que DateTime.Now

La seule manière que je trouvais pour améliorer la classe proposée consiste à utiliser code en ligne: DateTime.UtcNow + LocalUtcOffset au lieu d'appeler la méthode de classe

BTW essayer pour forcer le compilateur à compiler en ligne en utilisant [MethodImpl(MethodImplOptions.AggressiveInlining)] ne semblait pas accélérer les choses.