.net core 的时间日期类为啥这么慢, 跟 Java 至少几十倍的差距

2022-09-03 11:51:03 +08:00
 bthulu

测试环境: win10 ltsc 2021, .net6, java8
基于.net 没啥好用的日志组件, 就自己写了.
因为每条日志都要记录一个时间, 结果发现 C#的 DateTime.Now 是真的慢, 跟 java 的 new Date()对比了下,至少是几十倍的的性能差距.
调用 1 亿次 DateTime.Now 要好几秒, 而调用 1 亿次 new Date()只要几百毫秒.
而且我还是在 windows 上测试的, java 日期在 windows 上本身就比 linux 慢一两个数量级, 这要是放到 linux 下测试, .net core 日期操作岂不是要比 java 慢上几百倍?
java 还可以通过 System.currentMillis 直接获取当前时间戳, 省掉一大堆无必要的操作. .net core 我找了很久, 貌似没有这个东西.

5475 次点击
所在节点    .NET
43 条回复
PendingOni
2022-09-06 18:19:24 +08:00
![企业微信截图_16624594047008.png]( https://s2.loli.net/2022/09/06/A5nGKW4QZXg9e1j.png)
差不多是的,用时秒级,源码上也是不停的 New 出来的
bthulu
2022-09-06 19:45:47 +08:00
@PendingOni 你再试试.Now, 比.UtcNow 还要慢一倍以上
userforg2021
2022-09-07 17:17:20 +08:00
既然你都看到源码了,那就看下 Java 为什么快吧。

从 jdk11 中可以看到 Windows 获取时间使用的函数是 GetSystemTimeAsFileTime ;
https://github.com/openjdk/jdk/blob/jdk-11+28/src/hotspot/os/windows/os_windows.cpp#L917

再看.net6 ,可以看到.net 在系统支持时会使用更精确的时间函数 GetSystemTimePreciseAsFileTime ;
https://github.com/dotnet/runtime/blob/v6.0.8/src/libraries/System.Private.CoreLib/src/System/DateTime.Windows.cs#L134

GetSystemTimePreciseAsFileTime 函数在 win8 以上受支持:
https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime#requirements

这是一个慢的点。但是.net 的 DateTime 精度更高。另外.net 还会计算闰秒:
https://github.com/dotnet/runtime/blob/v6.0.8/src/libraries/System.Private.CoreLib/src/System/DateTime.Windows.cs#L23

这是第二个慢的点。也是为了精度考虑的。当然你可以说是.net 的“过度设计”,你不需要精确时间。。。那这个确实就需要自己动手了:

public unsafe static class SlimDateTime
{
private const long TicksPerMillisecond = 10000;
private const long TicksPerSecond = TicksPerMillisecond * 1000;
private const long TicksPerMinute = TicksPerSecond * 60;
private const long TicksPerHour = TicksPerMinute * 60;
private const long TicksPerDay = TicksPerHour * 24;

private const int DaysTo1601 = 584388;
private const int DaysTo1970 = 719162;

private const long FileTimeOffset = DaysTo1601 * TicksPerDay;

private const ulong KindUtc = 0x4000000000000000;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static DateTime UtcNow()
{
var ticks = GetTicks();
return *(DateTime*)&ticks;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong GetTicks() => OperatingSystem.IsWindows() ? Windows.GetTicks() : (ulong)DateTime.UtcNow.Ticks;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong UtcNowUnixTimeMilliseconds() => OperatingSystem.IsWindows() ? Windows.UtcNowUnixTimeMilliseconds() : (ulong)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();

private static class Windows
{
[DllImport("kernel32", EntryPoint = "GetSystemTimeAsFileTime")]
[SuppressGCTransition]
public extern static void GetSystemTimeAsFileTime(ulong* time);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong GetTicks()
{
ulong fileTime;
GetSystemTimeAsFileTime(&fileTime);
return fileTime + (FileTimeOffset | KindUtc);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong UtcNowUnixTimeMilliseconds()
{
ulong fileTime;
GetSystemTimeAsFileTime(&fileTime);
return (fileTime - ((DaysTo1970 - DaysTo1601) * TicksPerDay)) / TicksPerMillisecond;
}
}
}

其他的就不评价了,懒得打字;

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/877417

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX