.NET7如何优化Guid.Equals性能

 更新时间:2025年11月13日 08:54:32   作者:溪源More  
文章介绍了如何使用SIMD优化.NET7中的Guid.Equals()方法性能,通过将Guid定义为值类型并使用Vector128.LoadUnsafe方法加载内存中的数据,可以实现高效的比较操作,感兴趣的朋友跟随小编一起看看吧

简介

在之前的文章中,我们多次提到 Vector - SIMD 技术,也答应大家在后面分享更多.NET7 中优化的例子,今天就带来一个使用 SIMD 优化Guid.Equals()方法性能的例子。

为什么 Guid 能使用 SIMD 优化?

首先就需要介绍一些背景知识,那就是Guid它是什么,在我们人类眼中,Guid就是一串字符串,如下方所示的那样。

"D313CD46-2724-7359-84A0-9E73C861CCD2"

而在定义中,全局唯一标识符(GUID,Globally Unique Identifier)是一种由算法生成的二进制长度为128 位的数字标识符。GUID 主要用于在拥有多个节点、多台计算机的网络或系统中。在理想情况下,任何计算机和计算机集群都不会生成两个相同的 GUID。GUID 的总数达到了 2^128(3.4×10^38)个,所以随机生成两个相同 GUID 的可能性非常小,但并不为 0。GUID 一词有时也专指微软对 UUID 标准的实现。

大家可以看到我着重标记了它的位数是128 位,128 位意味着什么?就是如果比较两个 Guid 是否相等的话,不管是 64 位 CPU 还是 32 位的 CPU 需要多条指令比较多次。如果我们用上了 Vector?是不是会有更好的性能呢?

首先我们来看看 Guid 是如何定义的,看看能不能直接读取 128 位数据,从而用上 Vector。Guid 它是值类型的,是一个结构体。代码如下所示,我省略了部分信息。

public readonly partial struct Guid
    {
        ...
        private readonly int _a;   // Do not rename (binary serialization)
        private readonly short _b; // Do not rename (binary serialization)
        private readonly short _c; // Do not rename (binary serialization)
        private readonly byte _d;  // Do not rename (binary serialization)
        private readonly byte _e;  // Do not rename (binary serialization)
        private readonly byte _f;  // Do not rename (binary serialization)
        private readonly byte _g;  // Do not rename (binary serialization)
        private readonly byte _h;  // Do not rename (binary serialization)
        private readonly byte _i;  // Do not rename (binary serialization)
        private readonly byte _j;  // Do not rename (binary serialization)
        private readonly byte _k;  // Do not rename (binary serialization)
        ...
    }

可以看到它由 1 个 32 位 int,2 个 16 位的 short 和 8 个 8 位的 byte 组成,至于为什么需要这样组成,其实是一个标准化的东西,为了在生成和序列化时更快。

我们使用ObjectLayoutInspector可以打印出 Guid 的数据结构,数据结果如下图所示,和我们源码里面看到的一致:

那么 Guid 是否能使用 SIMD 优化的结论显而易见:

  • Guid 有 128 位,现在 CPU 都是 64 位或者 32 位,还存在提升空间
  • Guid 是结构体类型,结构体类型在内存中是连续存储,我们可以直接读取内存来访问整个结构体

SIMD 优化代码

根据我们前面文章中,Min 和 Max 方法在.NET7 被优化的经验,我们可以直接写下面这样的代码。

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool EqualsCore(in Guid left, in Guid right)
{
    // 检测硬件是否支持Vector128
    if (Vector128.IsHardwareAccelerated)
    {
        // 支持Vector128就好办了,直接加载比较
        return Vector128.LoadUnsafe(ref Unsafe.As<Guid, byte>(ref Unsafe.AsRef(in left))) == Vector128.LoadUnsafe(ref Unsafe.As<Guid, byte>(ref Unsafe.AsRef(in right)));
    }
    // 如果不支持,那么从Guid头部读取内存
    // 32位比较四次
    ref int rA = ref Unsafe.AsRef(in left._a);
    ref int rB = ref Unsafe.AsRef(in right._a);
    return rA == rB
        && Unsafe.Add(ref rA, 1) == Unsafe.Add(ref rB, 1)
        && Unsafe.Add(ref rA, 2) == Unsafe.Add(ref rB, 2)
        && Unsafe.Add(ref rA, 3) == Unsafe.Add(ref rB, 3);
}

在上面的代码中,我们可以看到不仅提供了 Vector 加速的方案,还有不支持回退的场景。不过那段 Vector 代码是不是不太好理解?我们逐个部分来解析一下。我们首先看左右的部分,右边也是同样的意思Vector128.LoadUnsafe(ref Unsafe.As<Guid, byte>(ref Unsafe.AsRef(in left)))

  • ref Unsafe.AsRef(in left) 是获取 left Guid 它的首地址指针,此时返回的其实是Guid*
  • ref Unsafe.As<Guid, byte>(...)Guid*指针转换为byte*指针
  • Vector128.LoadUnsafe(...) 由于 Guid 已经变为 Byte 指针,所以就能直接 LoadUnsafe 了

最后 right Guid 也使用相同的方式加载,最后使用==比较两个Vector是否相等就好了。其实==还使用了CompareEqualMoveMask两个指令,只是在.NET7 中 JIT 会把两个向量的比较给优化。看下方图片中红色框标记的部分,就是这两个指令。

那么.NET6 下==没有优化,那该怎么办呢?根据这里的汇编指令,Meziantou[1]大佬给出了.NET6 下同样功效的优化代码:

static class GuidExtensions
{
    public static bool OptimizedGuidEquals(in Guid left, in Guid right)
    {
        if (Sse2.IsSupported)
        {
            Vector128<byte> leftVector = Unsafe.ReadUnaligned<Vector128<byte>>(
                ref Unsafe.As<Guid, byte>(
                    ref Unsafe.AsRef(in left)));
            Vector128<byte> rightVector = Unsafe.ReadUnaligned<Vector128<byte>>(
                ref Unsafe.As<Guid, byte>(
                    ref Unsafe.AsRef(in right)));
            // 使用Sse2.CompareEqual()比较是否相等,它的返回值是一个128位向量,如果相等,该位置返回0xffff,否则返回0x0
            // CompareEqual的结果是128位的,我们可以通过Sse2.MoveMask()来重新排列成16位,最终看是否等于0xffff就好
            var equals = Sse2.CompareEqual(leftVector, rightVector);
            var result = Sse2.MoveMask(equals);
            return (result & 0xFFFF) == 0xFFFF;
        }
        return left == right;
    }
}

从下图的汇编代码中,可以看到是一样的效果:

总结

最终这一波操作下来,我们可以看到Guid.Equals的性能提升了 30%。如果你的程序中使用 Guid 作为数据库、对象主键的,只需要升级.NET7 或者用上面的GuidExtensions就能获得这样的性能提升。

参考资料

Meziantou: https://www.meziantou.net/faster-guid-comparisons-using-vectors-simd-in-dotnet.htm

到此这篇关于.NET7是如何优化Guid.Equals性能的?的文章就介绍到这了,更多相关.net优化guid.equals性能内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 禁止ViewState的3种解决方法

    禁止ViewState的3种解决方法

    默认情况下,ViewState是被启用的,比如提交表单后,表单中输入的值会自动保留。但是如果不需要保留,也可以将其禁用,这样可以节省资源。
    2013-03-03
  • asp.net采集页面上所有图像图片资源的具体方法

    asp.net采集页面上所有图像图片资源的具体方法

    这篇文章主要为大家详细介绍了asp.net采集页面上所有图像资源的具体方法,感兴趣的小伙伴们可以参考一下
    2016-03-03
  • ASP.NET MVC使用Log4Net记录异常日志并跳转到静态页

    ASP.NET MVC使用Log4Net记录异常日志并跳转到静态页

    这篇文章介绍了ASP.NET MVC使用Log4Net记录异常日志并跳转到静态页的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-09-09
  • asp.net URL中包含中文参数造成乱码的解决方法

    asp.net URL中包含中文参数造成乱码的解决方法

    中文乱码一直以来是WEB开发中比较常见的问题之一,对于初学者来说,各种各样的编码方式可能会有点不适应,本篇文章并不讲述这些编码,而是把自己遇到的一个小问题以及该问题的解决之法说明一下,希望对大家有用。
    2010-03-03
  • Visual Studio 2013+OpenCV2.4.10环境搭建教程

    Visual Studio 2013+OpenCV2.4.10环境搭建教程

    这篇文章主要为大家详细介绍了Visual Studio 2013+OpenCV2.4.10环境搭建教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • ASP.NET MVC5网站开发之总体概述(一)

    ASP.NET MVC5网站开发之总体概述(一)

    这篇文章主要为大家详细介绍了ASP.NET MVC5网站开发之总体概述,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-08-08
  • .Net Core使用Logger实现log写入本地文件系统

    .Net Core使用Logger实现log写入本地文件系统

    这篇文章介绍了.Net Core使用Logger实现log写入本地文件系统的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-06-06
  • .NET实用扩展方法详解

    .NET实用扩展方法详解

    这篇文章主要为大家详细介绍了.NET实用扩展方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-10-10
  • 关于ASP.NET页面打印技术的常用方法总结

    关于ASP.NET页面打印技术的常用方法总结

    B/S结构导致了Web应用程序中打印的特殊性;程序运行在浏览器中,打印机在本地,而文件确可能在服务器上,导致了打印控制不是很灵活,接下来介绍几种常见的打印技术,感兴趣的朋友可以了解下
    2013-01-01
  • ASP.NET4的自动启动特性浅析

    ASP.NET4的自动启动特性浅析

    本篇文章讨论一个你可以选择利用的ASP.NET4中小小的,但很棒的新特性,即自动启动,需要的朋友可以参考下
    2015-10-10

最新评论