Jon*_*n B 61 .net c# datetime timespan
是否可以Environment.TickCount用来计算时间跨度?
int start = Environment.TickCount;
// Do stuff
int duration = Environment.TickCount - start;
Console.WriteLine("That took " + duration " ms");
Run Code Online (Sandbox Code Playgroud)
因为TickCount已签名并将在25天后翻转(所有32位需要50天,但如果你想对数学有任何意义,你必须废弃已签名的位),看起来它太冒险了.
我正在使用DateTime.Now.这是最好的方法吗?
DateTime start = DateTime.Now;
// Do stuff
TimeSpan duration = DateTime.Now - start;
Console.WriteLine("That took " + duration.TotalMilliseconds + " ms");
Run Code Online (Sandbox Code Playgroud)
mis*_*ika 88
Environment.TickCount基于GetTickCount() WinAPI函数.它以毫秒为单位但实际精度约为15.6 ms.所以你不能测量更短的时间间隔(或者你会得到0)
注意:返回的值是Int32,因此此计数器每隔~49.7天滚动一次.你不应该用它来测量这么长的间隔.
DateTime.Ticks基于GetSystemTimeAsFileTime()WinAPI函数.它在100s纳秒(十分之一的微观键).DateTime.Ticks的实际精度取决于系统.在XP上,系统时钟的增量约为15.6 ms,与Environment.TickCount相同.在Windows 7上,它的精度是1毫秒(而Environemnt.TickCount仍然是15.6毫秒),但如果使用省电方案(通常在笔记本电脑上),它也可以降至15.6毫秒.
秒表基于QueryPerformanceCounter() WinAPI函数(但如果您的系统不支持高分辨率性能计数器,则使用DateTime.Ticks)
在使用StopWatch之前,请注意两个问题:
您可以通过简单的测试评估系统的精度:
static void Main(string[] args)
{
int xcnt = 0;
long xdelta, xstart;
xstart = DateTime.UtcNow.Ticks;
do {
xdelta = DateTime.UtcNow.Ticks - xstart;
xcnt++;
} while (xdelta == 0);
Console.WriteLine("DateTime:\t{0} ms, in {1} cycles", xdelta / (10000.0), xcnt);
int ycnt = 0, ystart;
long ydelta;
ystart = Environment.TickCount;
do {
ydelta = Environment.TickCount - ystart;
ycnt++;
} while (ydelta == 0);
Console.WriteLine("Environment:\t{0} ms, in {1} cycles ", ydelta, ycnt);
Stopwatch sw = new Stopwatch();
int zcnt = 0;
long zstart, zdelta;
sw.Start();
zstart = sw.ElapsedTicks; // This minimizes the difference (opposed to just using 0)
do {
zdelta = sw.ElapsedTicks - zstart;
zcnt++;
} while (zdelta == 0);
sw.Stop();
Console.WriteLine("StopWatch:\t{0} ms, in {1} cycles", (zdelta * 1000.0) / Stopwatch.Frequency, zcnt);
Console.ReadKey();
}
Run Code Online (Sandbox Code Playgroud)
Grz*_*nio 69
使用秒表课程.在msdn上有一个不错的例子:http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.aspx
Stopwatch stopWatch = Stopwatch.StartNew();
Thread.Sleep(10000);
stopWatch.Stop();
// Get the elapsed time as a TimeSpan value.
TimeSpan ts = stopWatch.Elapsed;
Run Code Online (Sandbox Code Playgroud)
小智 24
你为什么担心翻车?只要您测量的持续时间低于24.9天并计算相对持续时间,您就可以了.系统运行的时间并不重要,只要您只关心自己运行时间的一部分(而不是直接执行小于或大于开始和结束点的比较).即:
int before_rollover = Int32.MaxValue - 5;
int after_rollover = Int32.MinValue + 7;
int duration = after_rollover - before_rollover;
Console.WriteLine("before_rollover: " + before_rollover.ToString());
Console.WriteLine("after_rollover: " + after_rollover.ToString());
Console.WriteLine("duration: " + duration.ToString());
Run Code Online (Sandbox Code Playgroud)
正确打印:
before_rollover: 2147483642
after_rollover: -2147483641
duration: 13
Run Code Online (Sandbox Code Playgroud)
您不必担心标志位.像C一样,C#让CPU处理这个问题.
这是我在嵌入式系统中计算时间之前遇到的常见情况.例如,我永远不会直接比较afterrollover <afterrollover.我总是会执行减法来查找考虑翻转的持续时间,然后根据持续时间进行任何其他计算.
如果您正在寻找功能Environment.TickCount但没有创建新Stopwatch对象的开销,则可以使用静态Stopwatch.GetTimestamp()方法(以及Stopwatch.Frequency)来计算长时间跨度.因为GetTimestamp()返回a long,它不会溢出非常长的时间(超过10万年,在我用来写这个的机器上).它也比Environment.TickCount其最大分辨率为10到16毫秒更精确.
使用
System.Diagnostics.Stopwatch
Run Code Online (Sandbox Code Playgroud)
它有一个叫做的属性
EllapsedMilliseconds
Run Code Online (Sandbox Code Playgroud)
Environment.TickCount似乎比其他解决方案快得多:
Environment.TickCount 71
DateTime.UtcNow.Ticks 213
sw.ElapsedMilliseconds 1273
Run Code Online (Sandbox Code Playgroud)
测量结果由以下代码生成:
static void Main( string[] args ) {
const int max = 10000000;
//
//
for ( int j = 0; j < 3; j++ ) {
var sw = new Stopwatch();
sw.Start();
for ( int i = 0; i < max; i++ ) {
var a = Environment.TickCount;
}
sw.Stop();
Console.WriteLine( $"Environment.TickCount {sw.ElapsedMilliseconds}" );
//
//
sw = new Stopwatch();
sw.Start();
for ( int i = 0; i < max; i++ ) {
var a = DateTime.UtcNow.Ticks;
}
sw.Stop();
Console.WriteLine( $"DateTime.UtcNow.Ticks {sw.ElapsedMilliseconds}" );
//
//
sw = new Stopwatch();
sw.Start();
for ( int i = 0; i < max; i++ ) {
var a = sw.ElapsedMilliseconds;
}
sw.Stop();
Console.WriteLine( $"sw.ElapsedMilliseconds {sw.ElapsedMilliseconds}" );
}
Console.WriteLine( "Done" );
Console.ReadKey();
}
Run Code Online (Sandbox Code Playgroud)
这里有一个更新和更新的摘要,可能是这个主题中最有用的答案和评论+额外的基准和变体:
第一件事:正如其他人在评论中指出的那样,事情已经改变了过去几年,并且使用"现代"Windows(Win XP ++)和.NET,现代硬件没有或几乎没有理由不使用秒表().有关详细信息,请参阅MSDN 语录:
"QPC精度是否受到电源管理或Turbo Boost技术引起的处理器频率变化的影响?
否.如果处理器具有不变的TSC,则QPC不受这些变化的影响.如果处理器没有不变的TSC, QPC将恢复为不受处理器频率变化或Turbo Boost技术影响的平台硬件定时器.QPC能否可靠地用于多处理器系统,多核系统和具有超线程的系统?
是如何确定并验证QPC在我的机器上是否正常工作?
您不需要执行此类检查.哪些处理器具有非不变的TSC?[..进一步..]"
但是如果你不需要秒表()的精确度或者至少想要确切知道秒表(静态与基于实例)和其他可能变体的性能,请继续阅读:
我从cskwg接管了上面的基准测试,并扩展了代码以获得更多变体.我用几年前的i7 4700 MQ和C#7来测量VS 2017(更准确地说,用.NET 4.5.2编译,尽管是二进制文字,但它是C#6(用于此:字符串文字和'使用静态) ').特别是与上述基准相比,秒表()表现似乎有所改善.
这是一个循环中1000万次重复结果的例子,一如既往,绝对值并不重要,但即使相对值在其他硬件上也可能不同:
32位,没有优化的发布模式:
测量:GetTickCount64()[ms]:275
测量:Environment.TickCount [ms]:45
测量:DateTime.UtcNow.Ticks [ms]:167
测量:秒表:.ElapsedTicks [ms]:277
测量:秒表:.ElapsedMilliseconds [ ms]:548
测量:静态秒表.GetTimestamp [ms]:193
测量:秒表+转换为DateTime [ms]:551
将其与DateTime.Now.Ticks [ms]:9010进行比较
32位,发布模式,优化:
测量:GetTickCount64()[ms]:198
测量:Environment.TickCount [ms]:39
测量:DateTime.UtcNow.Ticks [ms]:66 (!)
测量:秒表:.ElapsedTicks [ms]:175
测量:秒表: .ElapsedMilliseconds [ms]:491
测量:静态秒表.GetTimestamp [ms]:175
测量:秒表+转换为DateTime [ms]: 510
将其与DateTime.Now.Ticks [ms]进行比较:8460
64位,没有优化的发布模式:
测量:GetTickCount64()[ms]:205
测量:Environment.TickCount [ms]:39
测量:DateTime.UtcNow.Ticks [ms]:127
测量:秒表:.ElapsedTicks [ms]:209
测量:秒表:.ElapsedMilliseconds [ ms]:285
测量:静态秒表.GetTimestamp [ms]:187
测量:秒表+转换为DateTime [ms]:319
将其与DateTime.Now.Ticks [ms]进行比较:3040
64位,发布模式,优化:
测量:GetTickCount64()[ms]:148
测量:Environment.TickCount [ms]:31 (它还值得吗?)
测量:DateTime.UtcNow.Ticks [ms]:76 (!)
测量:秒表:.ElapsedTicks [ ms]:178
测量:秒表:.ElapsedMilliseconds [ms]:226
测量:静态秒表.GetTimestamp [ms]:175
测量:秒表+转换为DateTime [ms]:246
将其与DateTime.Now.Ticks [ms]进行比较: 3020
可能非常有趣的是,创建一个DateTime值来打印秒表时间似乎几乎没有任何成本.有趣的是更具学术性而非实用性的方式是静态秒表略快(如预期的那样).一些优化点非常有趣.例如,我无法解释为什么只有32位的Stopwatch.ElapsedMilliseconds与其他变种相比是如此之慢,例如静态变体.这和DateTime.Now比64位速度加倍.
你可以看到:只有数百万次执行,秒表的时间开始变得重要.如果真的是这种情况(但是要过早地提防微优化),使用GetTickCount64()可能会很有趣,但特别是使用DateTime.UtcNow时,你有一个64位(长)计时器,其精度低于秒表,但更快,这样你就不必乱用32位"丑陋"的Environment.TickCount.
正如预期的那样,DateTime.Now是迄今为止最慢的.
如果你运行它,代码也会检索你当前的秒表准确度等等.
以下是完整的基准代码:
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using static System.Environment;
Run Code Online (Sandbox Code Playgroud)
[...]
[DllImport("kernel32.dll") ]
public static extern UInt64 GetTickCount64(); // Retrieves a 64bit value containing ticks since system start
static void Main(string[] args)
{
const int max = 10_000_000;
const int n = 3;
Stopwatch sw;
// Following Process&Thread lines according to tips by Thomas Maierhofer: https://codeproject.com/KB/testing/stopwatch-measure-precise.aspx
// But this somewhat contradicts to assertions by MS in: https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396#Does_QPC_reliably_work_on_multi-processor_systems__multi-core_system__and_________systems_with_hyper-threading
Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(1); // Use only the first core
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
Thread.CurrentThread.Priority = ThreadPriority.Highest;
Thread.Sleep(2); // warmup
Console.WriteLine($"Repeating measurement {n} times in loop of {max:N0}:{NewLine}");
for (int j = 0; j < n; j++)
{
sw = new Stopwatch();
sw.Start();
for (int i = 0; i < max; i++)
{
var tickCount = GetTickCount64();
}
sw.Stop();
Console.WriteLine($"Measured: GetTickCount64() [ms]: {sw.ElapsedMilliseconds}");
//
//
sw = new Stopwatch();
sw.Start();
for (int i = 0; i < max; i++)
{
var tickCount = Environment.TickCount; // only int capacity, enough for a bit more than 24 days
}
sw.Stop();
Console.WriteLine($"Measured: Environment.TickCount [ms]: {sw.ElapsedMilliseconds}");
//
//
sw = new Stopwatch();
sw.Start();
for (int i = 0; i < max; i++)
{
var a = DateTime.UtcNow.Ticks;
}
sw.Stop();
Console.WriteLine($"Measured: DateTime.UtcNow.Ticks [ms]: {sw.ElapsedMilliseconds}");
//
//
sw = new Stopwatch();
sw.Start();
for (int i = 0; i < max; i++)
{
var a = sw.ElapsedMilliseconds;
}
sw.Stop();
Console.WriteLine($"Measured: Stopwatch: .ElapsedMilliseconds [ms]: {sw.ElapsedMilliseconds}");
//
//
sw = new Stopwatch();
sw.Start();
for (int i = 0; i < max; i++)
{
var a = Stopwatch.GetTimestamp();
}
sw.Stop();
Console.WriteLine($"Measured: static Stopwatch.GetTimestamp [ms]: {sw.ElapsedMilliseconds}");
//
//
DateTime dt=DateTime.MinValue; // just init
sw = new Stopwatch();
sw.Start();
for (int i = 0; i < max; i++)
{
var a = new DateTime(sw.Elapsed.Ticks); // using variable dt here seems to make nearly no difference
}
sw.Stop();
//Console.WriteLine($"Measured: Stopwatch+conversion to DateTime [s] with millisecs: {dt:s.fff}");
Console.WriteLine($"Measured: Stopwatch+conversion to DateTime [ms]: {sw.ElapsedMilliseconds}");
Console.WriteLine();
}
//
//
sw = new Stopwatch();
var tickCounterStart = Environment.TickCount;
sw.Start();
for (int i = 0; i < max/10; i++)
{
var a = DateTime.Now.Ticks;
}
sw.Stop();
var tickCounter = Environment.TickCount - tickCounterStart;
Console.WriteLine($"Compare that with DateTime.Now.Ticks [ms]: {sw.ElapsedMilliseconds*10}");
Console.WriteLine($"{NewLine}General Stopwatch information:");
if (Stopwatch.IsHighResolution)
Console.WriteLine("- Using high-resolution performance counter for Stopwatch class.");
else
Console.WriteLine("- Using high-resolution performance counter for Stopwatch class.");
double freq = (double)Stopwatch.Frequency;
double ticksPerMicroSec = freq / (1000d*1000d) ; // microsecond resolution: 1 million ticks per sec
Console.WriteLine($"- Stopwatch accuracy- ticks per microsecond (1000 ms): {ticksPerMicroSec:N1}");
Console.WriteLine(" (Max. tick resolution normally is 100 nanoseconds, this is 10 ticks/microsecond.)");
DateTime maxTimeForTickCountInteger= new DateTime(Int32.MaxValue*10_000L); // tickCount means millisec -> there are 10.000 milliseconds in 100 nanoseconds, which is the tick resolution in .NET, e.g. used for TimeSpan
Console.WriteLine($"- Approximated capacity (maxtime) of TickCount [dd:hh:mm:ss] {maxTimeForTickCountInteger:dd:HH:mm:ss}");
// this conversion from seems not really accurate, it will be between 24-25 days.
Console.WriteLine($"{NewLine}Done.");
while (Console.KeyAvailable)
Console.ReadKey(false);
Console.ReadKey();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
71650 次 |
| 最近记录: |