Curieusement, votre code fonctionne parfaitement sur mon quad core sous Win7, générant des valeurs exactement à 2 ms à peu près à chaque fois. J'ai donc fait un test plus approfondi. Voici mon exemple de sortie pour Thread.Sleep(1)
. Le code imprime le nombre de ms entre des appels consécutifs à DateTime.UtcNow
dans une boucle:

Chaque ligne contient 100 caractères, et représente donc 100 ms de temps sur un « run propre ». Donc, cet écran couvre environ 2 secondes. La plus longue préemption était de 4ms; de plus, il y avait une période d'environ 1 seconde lorsque chaque itération prenait exactement 1 ms. C'est presque la qualité du système d'exploitation en temps réel! :)
donc j'ai essayé à nouveau, avec cette fois-ci Thread.Sleep(2)
:

Encore une fois, des résultats presque parfaits. Cette fois-ci, chaque rangée mesure 200ms de long, et il y a une course de près de 3 secondes où l'écart n'a jamais été que de 2ms exactement.
Naturellement, la prochaine chose à voir est la résolution réelle de DateTime.UtcNow
sur ma machine. Voici une course sans sommeil du tout; un .
est imprimé si UtcNow
n'a pas changé du tout :

Enfin, alors qu'il enquêtait sur une affaire étrange horodatages étant 15ms en dehors sur la même machine qui a produit les résultats ci-dessus, je n'ai plus dans les événements curieux suivants:

Il y a une fonction dans l'API Windows appelé timeBeginPeriod
, quelles applications peuvent utiliser pour augmenter temporairement la fréquence du minuteur, donc c'est probablement ce qui s'est passé ici. La documentation détaillée de la résolution de minuterie est disponible via le Hardware Dev Center Archive, en particulier Timer-Resolution.docx (un fichier Word).
Conclusions:
DateTime.UtcNow
peut une résolution beaucoup plus élevée que 15ms
Thread.Sleep(1)
peut dormir exactement 1ms
- Sur ma machine,
UtcNow
pousse croître de exactement 1ms à un moment (donner ou prendre une erreur d'arrondi - Reflector montre qu'il y a une division dans).
- Il est possible que le processus bascule en mode basse résolution, quand tout est basé sur 15,6 ms, et un mode haute résolution, avec des tranches de 1 ms, à la volée.
Voici le code:
static void Main(string[] args)
{
Console.BufferWidth = Console.WindowWidth = 100;
Console.WindowHeight = 20;
long lastticks = 0;
while (true)
{
long diff = DateTime.UtcNow.Ticks - lastticks;
if (diff == 0)
Console.Write(".");
else
switch (diff)
{
case 10000: case 10001: case 10002: Console.ForegroundColor=ConsoleColor.Red; Console.Write("1"); break;
case 20000: case 20001: case 20002: Console.ForegroundColor=ConsoleColor.Green; Console.Write("2"); break;
case 30000: case 30001: case 30002: Console.ForegroundColor=ConsoleColor.Yellow; Console.Write("3"); break;
default: Console.Write("[{0:0.###}]", diff/10000.0); break;
}
Console.ForegroundColor = ConsoleColor.Gray;
lastticks += diff;
}
}
Il se trouve, il existe une fonction non documentée qui peut modifier la résolution de la minuterie. Je n'ai pas étudié les détails, mais j'ai pensé que je posterais un lien ici: NtSetTimerResolution
.
Bien sûr, j'ai fait en sorte que le système d'exploitation soit aussi inactif que possible, et il dispose de quatre cœurs de processeur assez puissants. Si je charge tous les quatre cœurs à 100%, l'image change complètement, avec de longues préemptions partout.
Toute personne venant ici, le TL; DR http://msdn.microsoft.com/en-us/library/ms644904%28VS.85%29.aspx – AnotherUser