基准日期时间

时间:2018-04-11 04:54:52

标签: c# benchmarking

在尝试将分钟/秒舍入到最接近的小时(在这种情况下忽略分/秒部分)时,对于以下行为有点好奇。

我尝试了两种方法,并使用BenchMarkDotNet进行基准测试。

private DateTime testData = DateTime.Now;

[Benchmark]
public DateTime CeilingUsingNewOperator() => new DateTime(testData.Year,testData.Month,testData.Day,testData.Hour + 1,0,0);
[Benchmark]
public DateTime CeilingUsingAddOperator() => testData.AddHours(1).AddMinutes(-testData.Minute).AddSeconds(-testData.Second);

以下是结果。

+-------------------------+-----------+----------+----------+
|         Method          |   Mean    |  Error   |  StdDev  |
+-------------------------+-----------+----------+----------+
| CeilingUsingNewOperator | 207.99 ns | 3.465 ns | 3.072 ns |
| CeilingUsingAddOperator | 108.74 ns | 1.429 ns | 1.337 ns |
+-------------------------+-----------+----------+----------+

我很好奇为什么New Operator会慢一些,如果我假设,每次我们在第二种方法中调用AddX方法时,我们都会得到一个Datetime。

有人可以解释一下吗?

1 个答案:

答案 0 :(得分:7)

可以使用进一步的基准来验证这一点,但我强烈怀疑这是因为AddHoursAddMinutesAddSeconds方法都可以在不执行任何复杂的日期/时间算法的情况下工作。他们只需要:

  • 将单位中的刻度数(小时,分钟,秒)乘以方法cal中指定的单位数
  • 将其添加到原始DateTime
  • 中的刻度数
  • 使用新的滴答数创建新的DateTime

您还使用MinuteSecond属性,但可以在不计算月/日/年值的情况下计算它们。

将其与需要的“单一构造函数”调用进行比较:

  • 计算一年(昂贵)
  • 计算月份(昂贵)
  • 锻炼一天(昂贵)
  • 计算小时(便宜)
  • 拿一个新的一年/月/日/小时/分钟/秒计算出蜱数(贵)

计算年,月和日的代码需要“理解”公历 - 为了提取信息,要执行的计算要复杂得多。有些可以缓存(例如每年开始时的刻度数)但是在内存访问方面你会失去一些参考位置。

我希望大多数有效的方法是直接计算滴答的方法,只需简单算术:

long originalTicks = testData.Ticks;
long hoursSinceEpoch = originalTicks / TimeSpan.TicksPerHour;
long newTicks = hoursSinceEpoch * TimeSpan.TicksPerHour;
return new DateTime(newTicks, testData.Kind);

一个重要的缺点:我认为当DateTimeKindLocal时,围绕夏令时边界会有问题,因为实际上有四种种而不是三种我们通常使用(UtcLocalUnspecified)。 Local实际上被分成两部分,以“知道”当前一个选项和后一个选项之间的值不明确时,正在表示哪个日期/时间。如果你没有使用Local类,那应该没问题。