我知道这已经涉及到微观优化领域,但我很好奇为什么调用DateTime.Now和DateTime.UtcNow会如此"昂贵"。我有一个样本程序,运行几个场景来执行一些"工作"(增加计数器),并尝试在1秒钟内完成。我有几种方法可以让它在有限的时间内执行工作。示例表明,DateTime.Now和DateTime.UtcNow比Environment.TickCount慢得多,但即使与让单独的线程休眠1秒钟然后设置值以指示工作线程停止相比,后者也很慢。
我的问题是:
- 我知道UtcNow更快,因为它没有时区信息,为什么它仍然比TickCount慢那么多?
- 为什么读取布尔型变量比读取整型变量更快?
- 处理这些类型的场景的理想方式是什么?你需要允许某些东西运行有限的时间,但你不想浪费更多的时间来检查时间而不是真正地做事情?
请原谅示例的冗长:
class Program
{
private static volatile bool done = false;
private static volatile int doneInt = 0;
private static UInt64 doneLong = 0;
private static ManualResetEvent readyEvent = new ManualResetEvent(false);
static void Main(string[] args)
{
MethodA_PrecalcEndTime();
MethodB_CalcEndTimeEachTime();
MethodC_PrecalcEndTimeUsingUtcNow();
MethodD_EnvironmentTickCount();
MethodX_SeperateThreadBool();
MethodY_SeperateThreadInt();
MethodZ_SeperateThreadLong();
Console.WriteLine("Done...");
Console.ReadLine();
}
private static void MethodA_PrecalcEndTime()
{
int cnt = 0;
var doneTime = DateTime.Now.AddSeconds(1);
var startDT = DateTime.Now;
while (DateTime.Now <= doneTime)
{
cnt++;
}
var endDT = DateTime.Now;
Console.WriteLine("Time Taken: {0,30} Total Counted: {1,20}", endDT.Subtract(startDT), cnt);
}
private static void MethodB_CalcEndTimeEachTime()
{
int cnt = 0;
var startDT = DateTime.Now;
while (DateTime.Now <= startDT.AddSeconds(1))
{
cnt++;
}
var endDT = DateTime.Now;
Console.WriteLine("Time Taken: {0,30} Total Counted: {1,20}", endDT.Subtract(startDT), cnt);
}
private static void MethodC_PrecalcEndTimeUsingUtcNow()
{
int cnt = 0;
var doneTime = DateTime.UtcNow.AddSeconds(1);
var startDT = DateTime.Now;
while (DateTime.UtcNow <= doneTime)
{
cnt++;
}
var endDT = DateTime.Now;
Console.WriteLine("Time Taken: {0,30} Total Counted: {1,20}", endDT.Subtract(startDT), cnt);
}
private static void MethodD_EnvironmentTickCount()
{
int cnt = 0;
int doneTick = Environment.TickCount + 1000; // <-- should be sane near where the counter clocks...
var startDT = DateTime.Now;
while (Environment.TickCount <= doneTick)
{
cnt++;
}
var endDT = DateTime.Now;
Console.WriteLine("Time Taken: {0,30} Total Counted: {1,20}", endDT.Subtract(startDT), cnt);
}
private static void MethodX_SeperateThreadBool()
{
readyEvent.Reset();
Thread counter = new Thread(CountBool);
Thread waiter = new Thread(WaitBool);
counter.Start();
waiter.Start();
waiter.Join();
counter.Join();
}
private static void CountBool()
{
int cnt = 0;
readyEvent.WaitOne();
var startDT = DateTime.Now;
while (!done)
{
cnt++;
}
var endDT = DateTime.Now;
Console.WriteLine("Time Taken: {0,30} Total Counted: {1,20}", endDT.Subtract(startDT), cnt);
}
private static void WaitBool()
{
readyEvent.Set();
Thread.Sleep(TimeSpan.FromSeconds(1));
done = true;
}
private static void MethodY_SeperateThreadInt()
{
readyEvent.Reset();
Thread counter = new Thread(CountInt);
Thread waiter = new Thread(WaitInt);
counter.Start();
waiter.Start();
waiter.Join();
counter.Join();
}
private static void CountInt()
{
int cnt = 0;
readyEvent.WaitOne();
var startDT = DateTime.Now;
while (doneInt<1)
{
cnt++;
}
var endDT = DateTime.Now;
Console.WriteLine("Time Taken: {0,30} Total Counted: {1,20}", endDT.Subtract(startDT), cnt);
}
private static void WaitInt()
{
readyEvent.Set();
Thread.Sleep(TimeSpan.FromSeconds(1));
doneInt = 1;
}
private static void MethodZ_SeperateThreadLong()
{
readyEvent.Reset();
Thread counter = new Thread(CountLong);
Thread waiter = new Thread(WaitLong);
counter.Start();
waiter.Start();
waiter.Join();
counter.Join();
}
private static void CountLong()
{
int cnt = 0;
readyEvent.WaitOne();
var startDT = DateTime.Now;
while (doneLong < 1)
{
cnt++;
}
var endDT = DateTime.Now;
Console.WriteLine("Time Taken: {0,30} Total Counted: {1,20}", endDT.Subtract(startDT), cnt);
}
private static void WaitLong()
{
readyEvent.Set();
Thread.Sleep(TimeSpan.FromSeconds(1));
doneLong = 1;
}
}