2009-10-13 74 views
24

一位同事和我在这个问题上来回回顾,我希望得到一些外界的意见,看看我提出的解决方案是否是一个好主意。优化DateTime.Now的替代方案

首先,免责声明:我意识到“优化DateTime.Now”这个概念听起来对某些人来说很疯狂。我有一对夫妇先发制人的防御:

  1. 我有时怀疑,这些人谁总是说,“电脑是快速,可读性总是来优化前”往往从经验上讲开发应用中的性能,虽然它可能是重要,不是重要。我谈论的是需要尽可能接近瞬间发生的事情 - 比如在几纳秒内(在某些行业,这个确实是很重要 - 例如实时高频交易)。
  2. 即使考虑到这一点,我在下面描述的替代方法实际上是非常可读的。这不是一个奇怪的黑客攻击,只是一种可靠,快速运行的简单方法。
  3. 我们运行测试。 DateTime.Now慢(相对来说)。下面的方法更快。

现在,问题本身。

基本上,从测试中,我们发现DateTime.Now需要大约25个刻度(大约2.5微秒)才能运行。当然,这是平均数以千计至数百万的电话。看起来第一次通话实际上需要很长时间,后续通话要快得多。但是,仍然有25个蜱是平均值。

但是,我和我的同事注意到DateTime.UtcNow的运行时间要少很多 - 平均只有0.03微秒。

考虑到我们的应用程序将永远不会被运行时有夏令时的变化,我的建议是创建下面的类:

public static class FastDateTime { 
    public static TimeSpan LocalUtcOffset { get; private set; } 

    public static DateTime Now { 
     get { return DateTime.UtcNow + LocalUtcOffset; } 
    } 

    static FastDateTime() { 
     LocalUtcOffset = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now); 
    } 
} 

换句话说,确定UTC的偏移当地时区一次 - 启动时 - 从此时起,利用DateTime.UtcNow的速度通过FastDateTime.Now获得当前时间。

如果UTC偏移量在应用程序运行期间发生变化(例如,应用程序在夜间运行),我可以看到这是一个问题;但正如我已经说过,在我们的的情况下,这不会发生。

我的同事对于如何做到这一点有不同的看法,这有点太牵扯到我在这里解释。最后,据我所知,我们的两种方法都返回了一个精确的结果,我的速度稍微快了一些(〜0.07微秒,比0.21微秒)。

我想知道的是:

  1. 我失去了一些东西在这里?鉴于上述事实,该应用程序只能在单一日期的时间范围内运行,是否安全?
  2. 其他人可能会想到一个更快的获取当前时间的方式?
+2

在进行这些简化时,DST转换是通常的疏忽,并且您已经规定这不会成为问题。它引起人们的警惕,发现他们(和他们的应用软件)生活在2个时区内,没有移动一英寸。而且测试套件捕获这个的唯一时间就是它在DST转换过程中恰好运行的情况,这是一个非常棘手的问题,这种情况很少发生(或者被模拟为测试套件的一部分,我认为这是偶数更稀有的东西)。 – PaulMcG 2009-10-13 17:52:59

回答

26

您可以只使用DateTime.UtcNow,并且只能在数据呈现时转换为本地时间吗?您已经确定DateTime.UtcNow速度更快,并且可以消除DST周围的任何歧义。的

DateTime.Now 

DateTime.UtcNow + LocalUtcOffset 

结果之间

+2

+1我读过UtcNow要快得多,这对我来说是令人惊讶的。 http://blogs.msdn.com/clrperfblog/archive/2009/09/08/computing-time-in-net.aspx – kenny 2009-12-09 10:06:35

+2

我打算继续,只是接受这个答案,因为它使得很多感觉。不幸的是,我不认为我们会这样做(至少现在还没有),因为我们必须改变大量的代码。但这是一个令人难以置信的合理建议。 – 2010-03-10 04:16:46

+0

这是重要的演示文稿:没有单个本地时间,因此只有在演示时才能计算。 – 2011-08-24 09:37:02

2

要回答以相反的顺序:

2)我想不出一个更快的方法。

1)如果在管道中的任何框架的改进,比如他们有just announced for System.IO

很难确保有关安全,但它的东西,正迫切需要大量的单元测试,这将是值得一试。夏令时想到。系统之一显然非常激烈,而你的系统却不是。

7

一个差别是Kind属性的值 - 分别本地VS UTC。如果生成的DateTime正在传递给第三方库,请考虑返回

DateTime.SpecifyKind(DateTime.UtcNow + LocalUtcOffset, DateTimeKind.Local) 
4

我喜欢你的解决方案。 我做了一些测试,看看它是如何更快相比普通DateTime.Now

DateTime.UtcNow比使用DateTime.UtcNow足够好,如果我们只是在持续时间,而不是时间本身感兴趣DateTime.Now

快117倍。如果我们需要的是计算特定代码段的时长(做duration= End_time - Start_time),那么时区并不重要,并且DateTime.UtcNow就足够了。

但是,如果我们需要时间本身那么我们需要做的 DateTime.UtcNow + LocalUtcOffset

只需添加时间跨度减慢一点点 ,现在根据我的测试,我们比普通DateTime.Now

更快的只是49倍

如果我们把这个计算放在一个单独的函数/类中,那么调用这个方法的速度会更慢,我们的速度只有34倍。

但即使是34倍快!

总之, 使用DateTime.UtcNowDateTime.Now

的唯一方法快得多,我发现改善建议类是使用 内嵌代码:DateTime.UtcNow + LocalUtcOffset 而不是调用类方法

BTW尝试的通过使用[MethodImpl(MethodImplOptions.AggressiveInlining)] 强制编译器编译为内联似乎并没有加快速度。