gpt4 book ai didi

c# - 为什么 DateTime.Now DateTime.UtcNow 如此缓慢/昂贵

转载 作者:IT王子 更新时间:2023-10-29 04:41:19 28 4
gpt4 key购买 nike

我意识到这离微优化领域太远了,但我很想知道为什么调用 DateTime.Now 和 DateTime.UtcNow 如此“昂贵”。我有一个示例程序,它运行几个场景来做一些“工作”(添加到一个计数器)并尝试这样做 1 秒钟。我有几种方法可以让它在有限的时间内完成工作。这些示例表明 DateTime.Now 和 DateTime.UtcNow 比 Environment.TickCount 慢得多,但即使这样也比让一个单独的线程休眠 1 秒然后设置一个值以指示工作线程停止相比慢。

所以我的问题是:

  • 我知道 UtcNow 更快,因为它没有时区信息,为什么它仍然比 TickCount 慢这么多?
  • 为什么读取 bool 值比读取整数快?
  • 处理这些类型的场景的理想方法是什么?您需要允许某些东西运行有限的时间,但您又不想浪费更多时间来检查时间而不是实际执行工作?<

请原谅这个例子的冗长:

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

}

最佳答案

TickCount 只是读取一个不断增加的计数器。这几乎是您可以做的最简单的事情。

DateTime.UtcNow 需要查询系统时间 - 不要忘记虽然 TickCount 对用户更改时钟或 NTP 之类的事情一无所知, UtcNow 必须考虑到这一点。

现在您已经表达了性能问题 - 但在您给出的示例中,您所做的只是递增计数器。我希望在您的真实 代码中,您将做更多的工作。如果您正在做大量 的工作,这可能会使 UtcNow 所花费的时间相形见绌。在做任何其他事情之前,您应该对其进行衡量,以确定您是否真的在尝试解决一个不存在的问题。

如果您确实需要改进,那么:

  • 您可以使用计时器而不是显式创建新线程。框架中有各种计时器,在不知道您的确切情况的情况下,我无法建议使用哪种计时器最明智 - 但感觉这是比启动线程更好的解决方案。
  • 您可以测量任务的几次迭代,然后猜测实际需要多少次。然后,您可能希望执行一半的迭代次数,评估所用的时间,然后相应地调整剩余周期数。当然,如果每次迭代所花费的时间变化很大,这将不起作用。

关于c# - 为什么 DateTime.Now DateTime.UtcNow 如此缓慢/昂贵,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4075525/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com