Я понимаю, что это слишком далеко в области микрооптимизации, но мне любопытно понять, почему вызовы DateTime.Now и DateTime.UtcNow настолько «дороги». У меня есть пример программы, которая запускает несколько сценариев выполнения некоторой «работы» (добавление к счетчику) и пытается сделать это в течение 1 секунды. У меня было несколько подходов к тому, чтобы заставить его работать в течение ограниченного времени. Примеры показывают, что DateTime.Now и DateTime.UtcNow значительно медленнее, чем Environment.TickCount, но даже это медленно по сравнению с тем, чтобы просто позволить отдельному потоку спать на 1 секунду, а затем установить значение, указывающее, что рабочий поток остановился.
Итак, мои вопросы следующие:
Простите, пожалуйста, за многословие примера:
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;
}
}