.NET 元组和等于性能

2024-07-03

这是我直到今天才注意到的事情。显然,常用的元组类的 .NET 实现(Tuple<T>, Tuple<T1, T2>等)导致拳击处罚对于值类型当执行基于相等的操作时。

以下是该类在框架中的实现方式(来源来自 ILSpy):

public class Tuple<T1, T2> : IStructuralEquatable 
{
    public T1 Item1 { get; private set; }
    public T2 Item2 { get; private set; }

    public Tuple(T1 item1, T2 item2)
    {
        this.Item1 = item1;
        this.Item2 = item2;
    }

    public override bool Equals(object obj)
    {
        return this.Equals(obj, EqualityComparer<object>.Default);
    }

    public override int GetHashCode()
    {
        return this.GetHashCode(EqualityComparer<object>.Default);
    }

    public bool Equals(object obj, IEqualityComparer comparer)
    {
        if (obj == null)
        {
            return false;
        }

        var tuple = obj as Tuple<T1, T2>;
        return tuple != null 
            && comparer.Equals(this.Item1, tuple.Item1) 
            && comparer.Equals(this.Item2, tuple.Item2);
    }

    public int GetHashCode(IEqualityComparer comparer)
    {
        int h1 = comparer.GetHashCode(this.Item1);
        int h2 = comparer.GetHashCode(this.Item2);

        return (h1 << 5) + h1 ^ h2;
    }
}

我看到的问题是它会导致两阶段装箱-拆箱,例如Equals电话,一,在comparer.Equals将物品装箱,两个,EqualityComparer<object>称为非通用的 Equals这反过来又必须在内部将项目拆箱为原始类型。

相反,他们为什么不做类似的事情:

public override bool Equals(object obj)
{
    var tuple = obj as Tuple<T1, T2>;
    return tuple != null
        && EqualityComparer<T1>.Default.Equals(this.Item1, tuple.Item1)
        && EqualityComparer<T2>.Default.Equals(this.Item2, tuple.Item2);
}

public override int GetHashCode()
{
    int h1 = EqualityComparer<T1>.Default.GetHashCode(this.Item1);
    int h2 = EqualityComparer<T2>.Default.GetHashCode(this.Item2);

    return (h1 << 5) + h1 ^ h2;
}

public bool Equals(object obj, IEqualityComparer comparer)
{
    var tuple = obj as Tuple<T1, T2>;
    return tuple != null
        && comparer.Equals(this.Item1, tuple.Item1)
        && comparer.Equals(this.Item2, tuple.Item2);
}

public int GetHashCode(IEqualityComparer comparer)
{
    int h1 = comparer.GetHashCode(this.Item1);
    int h2 = comparer.GetHashCode(this.Item2);

    return (h1 << 5) + h1 ^ h2;
}

我很惊讶地看到在 .NET 元组类中以这种方式实现相等。我使用元组类型作为其中一本字典的键。

是否有任何理由必须如第一个代码所示来实现?在这种情况下使用此类有点令人沮丧。

我认为代码重构和非重复数据不应该是主要关注点。同样的非通用/拳击实现已经落后了IStructuralComparable也是,但是自从IStructuralComparable.CompareTo较少使用,这通常不是问题。


我用第三种方法对上述两种方法进行了基准测试,该方法仍然不那么费力,如下所示(仅是要点):

public override bool Equals(object obj)
{
    return this.Equals(obj, EqualityComparer<T1>.Default, EqualityComparer<T2>.Default);
}

public bool Equals(object obj, IEqualityComparer comparer)
{
    return this.Equals(obj, comparer, comparer);
}

private bool Equals(object obj, IEqualityComparer comparer1, IEqualityComparer comparer2)
{
    var tuple = obj as Tuple<T1, T2>;
    return tuple != null
        && comparer1.Equals(this.Item1, tuple.Item1)
        && comparer2.Equals(this.Item2, tuple.Item2);
} 

对于几个Tuple<DateTime, DateTime>字段 a 1000000Equals来电。这是结果:

第一种方法(原始 .NET 实现)- 310 毫秒

第二种方法 - 60 毫秒

第三种方法 - 130 毫秒

默认实现比最佳解决方案慢大约 4-5 倍。


您想知道是否“必须”以这种方式实施。简而言之,我会说不:有许多功能相同的实现。

但是为什么现有的实现如此明确地使用EqualityComparer<object>.Default?这可能只是写这篇文章的人在心理上优化“错误”的情况,或者至少与您的内循环速度场景不同。根据他们的基准,这可能看起来是“正确”的事情。

但什么样的基准情景可以引导他们做出这样的选择呢?他们的优化目标似乎是优化 EqualityComparer 类模板实例化的最小数量。他们可能会选择这个,因为模板实例化会带来内存或加载时间成本。如果是这样,我们可以猜测他们的基准场景可能是基于应用程序启动时间或内存使用情况,而不是一些紧密循环场景。

这是支持该理论的一个知识点(通过使用确认偏差发现:) -如果 T 是结构体,则 EqualityComparer 实现方法体不能共享。摘自http://blogs.microsoft.co.il/sasha/2012/09/18/runtime-representation-of-genericspart-2/ http://blogs.microsoft.co.il/sasha/2012/09/18/runtime-representation-of-genericspart-2/

当 CLR 需要创建封闭泛型类型的实例时, 例如List,它根据方法表和EEClass创建 开放式。与往常一样,方法表包含方法指针,其中 由 JIT 编译器动态编译。然而,有一个 这里的关键优化:在封闭泛型上编译方法体 具有引用类型参数的类型可以共享。 [...] 相同 这个想法不适用于值类型。例如,当 T 很长时, 赋值语句 items[size] = item 需要不同的 指令,因为必须复制 8 个字节而不是 4 个字节。甚至更大 值类型甚至可能需要多个指令;等等。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

.NET 元组和等于性能 的相关文章

  • .Net WinForm 应用程序是否有一个可以显示 HTML 的控件

    我有一个 net 3 5 WinForms 应用程序 想要在其中一个表单上显示一些 html 我可以使用一个控件来实现此目的吗 是的 当然是 WebBrowser 控件
  • 在二进制数据中搜索文本

    我有一个包含文本的二进制数据 文字是已知的 搜索该文本的快速方法是什么 作为一个例子 This is text 1 lt Assume this line is 3 MB of binary data Now This is text 2
  • 在编写任何锁之前我应该​​对多线程问题进行单元测试吗?

    我正在编写一个我知道需要锁的类 因为该类必须是线程安全的 但由于我是测试驱动开发 我知道在为其创建测试之前我无法编写一行代码 我发现很难做到 因为测试最终会变得非常复杂 在这些情况下你通常会做什么 有什么工具可以帮助解决这个问题吗 这个问题
  • 如何在.Net 中将上传的 RGB 格式图像转换为 CMYK 格式?

    我需要将图像转换并保存为 CMYK 格式 当我上传 RGB 格式的图像时 我需要将其转换为 CMYK 在 Net中可能吗 谢谢 正如其他人提到的 NET 本身并不支持图像色彩空间调整 然而 图像魔术师 http www imagemagic
  • java.util.jar.jarfile.init() 方法执行时间太长

    Story 我正在解决 Web 应用程序的一些性能问题 应用背景 该应用程序是用Java with Velocity Template Engine 以及前端javaScript使用Tomcat9服务器 Problem 当我让应用程序运行
  • .net 新进程沙箱用于不受信任的代码

    所以我需要在新进程中运行动态编译的不受信任的代码 我找到了如何在新的 AppDomain http msdn microsoft com en us library bb763046 aspx 中执行此操作 但没有在新进程中执行此操作 可以
  • 将我的项目中的表单添加到另一个项目

    我有一个项目 其中有一个窗体 其本身有多个对象 控件 我想将此表单添加到另一个解决方案中的另一个项目中 我怎样才能做到这一点 谢谢 您的意思是您的项目中有一个表单并且您想要将其添加到另一个项目在其他一些解决方案中 如果那么情况就是这样 Fo
  • jQuery 验证 - 获取 invalidHandler 中错误字段的列表

    我在页面上使用 jQuery 验证 在调用 invalidHandler 期间 我希望能够访问所有验证失败的表单元素的列表 该函数作为选项之一传递给 jQuery validate 方法 invalidHandler function fo
  • Winforms:如何获取透明表单上的透明控件的鼠标事件

    我有一个透明的表单 覆盖在 c NET winforms 应用程序中的桌面 透明度是通过设置BackColor为亮橙色 然后设置TransparencyKey到同样明亮的橙色 到目前为止 这效果很好 并且创建了透明的形式 然后我想在透明表单
  • 通过字典有效地替换 pandas 系列中的值

    如何替换 Pandas 系列中的值s通过字典d已经被问了很多次了 推荐方法 1 https stackoverflow com a 40855794 9209546 2 https stackoverflow com a 40528697
  • 从 PowerShell 挂起或休眠

    我有兴趣使用 Windows PowerShell 挂起或休眠计算机 你如何实现这一目标 我已经知道Stop Computer and Restart Computercmdlet 它们是开箱即用的 但它们并没有实现我想要的功能 您可以使用
  • 创建补丁来升级 .NET 应用程序

    我想为我的 NET 应用程序创建一个补丁 要求是 找到安装目录 用新文件覆盖旧文件 重新启动 Windows 服务 我想将更新程序发送给用户 以便他们只需运行它并更新应用程序 我的原始安装程序是使用 Visual Studio 部署项目创建
  • EJB 与 WebService?性能角度

    好吧 我们现在要根据情况做出决定 我认为 stackoverflow 是最好的讨论场所 背景 我们有 2 个 JVM 企业应用程序服务器 每台服务器上部署一个应用程序 我们需要启用从一台机器到另一台机器的业务功能调用 假设一个是客户端 另一
  • 使用参数的 SQL Server 查询比使用常量字符串的查询花费的时间更长

    我在使用 MS SQL Server 2008 时遇到一个问题 当我使用硬编码字符串作为参数执行查询时 查询运行得很快 但是当我使用字符串参数时 查询需要更长的时间 常量字符串查询需要1秒 而其他则需要11秒 以下是代码 常量字符串 1秒
  • 计算字符串中某个字符出现的次数? [复制]

    这个问题在这里已经有答案了 可能的重复 计算字符串中特定字符的出现次数 https stackoverflow com questions 5193893 count specific character occurances in str
  • 在 C# 中访问交换电子邮件

    你知道有没有办法吗 我用过这个图书馆 http www codeproject com KB IP NetPopMimeClient aspx 20访问 pop3 服务器 但它不能与 Exchange 服务器一起使用 您是否知道任何其他库或
  • XAML 页面中的 Bindable 值存在问题

    我有一个保龄球回顾示例代码 其中输入了 3 场比赛并总结在系列列中 我遇到的问题是系列列没有按照我的预期进行更新 显然 我做错了什么 但看不到我做错了什么 以下是支持该应用程序的代码
  • 如何使文本框的自动完成列表可编辑?

    我有一个包含很多内容的应用程序TextBox使用自动完成的控件 每个人都使用AutoCompleteMode CustomSource从关联的获取自动完成文本AutoCompleteStringCollection 每当用户在其中输入新值时
  • 在 C# 中捕获异常

    我有一个简单的添加按钮 ADD Click 代码是 protected void Add Click object sender EventArgs e string strConnectionString ConfigurationMan
  • 如何解决有关 TcpListener: 请使用 TcpListener(IPAddress localaddr, int port) 的警告?

    我创建了一个新表单 在顶部我做了 using System using System Collections Generic using System ComponentModel using System Data using Syste

随机推荐

  • 处理php中表单的多个输入

    我想知道如何处理具有多个属性的表单的多个输入 此代码生成我的字段
  • 处理php中表单的多个输入

    我想知道如何处理具有多个属性的表单的多个输入 此代码生成我的字段
  • 处理程序未在 Instrumentation Test 中执行 Runnable

    我编写了一个 Android 仪器测试 它调用我的服务并通过广播接收答案 要测试的代码与服务通信 使用处理程序 在测试我的测试过程中 我注意到处理程序的行为不符合预期 所以我编写了一个测试来检查这种行为 import android os
  • 处理程序未在 Instrumentation Test 中执行 Runnable

    我编写了一个 Android 仪器测试 它调用我的服务并通过广播接收答案 要测试的代码与服务通信 使用处理程序 在测试我的测试过程中 我注意到处理程序的行为不符合预期 所以我编写了一个测试来检查这种行为 import android os
  • 使用 SSL 的 Kafka SASL/PLAIN 设置

    我正在尝试在我们的 Kafka 环境中使用 SSL 配置 SASL PLAIN SSL 部分已完成 但在启动 Zookeeper 时遇到以下错误 有人为 Zookeeper 和代理配置了带有 SSL 的 SASL PLAIN 吗 服务器代理
  • 使用 SSL 的 Kafka SASL/PLAIN 设置

    我正在尝试在我们的 Kafka 环境中使用 SSL 配置 SASL PLAIN SSL 部分已完成 但在启动 Zookeeper 时遇到以下错误 有人为 Zookeeper 和代理配置了带有 SSL 的 SASL PLAIN 吗 服务器代理
  • Gulp:仅在编辑导入的 SCSS 文件时编译更改的文件并编译父文件

    工作中我们常用Ruby来编译SCSS 我在 PhpStorm 中将 Ruby 编译器设置为文件观察器 当我编辑由另一个文件导入的部分时 与祖先文件对应的 CSS 文件会毫不费力地更新 我想让 Gulp 和 Libsass 以同样的方式工作
  • Gulp:仅在编辑导入的 SCSS 文件时编译更改的文件并编译父文件

    工作中我们常用Ruby来编译SCSS 我在 PhpStorm 中将 Ruby 编译器设置为文件观察器 当我编辑由另一个文件导入的部分时 与祖先文件对应的 CSS 文件会毫不费力地更新 我想让 Gulp 和 Libsass 以同样的方式工作
  • IPython 笔记本 - 无法导出为 pdf

    我正在尝试将 IPython 笔记本导出为 pdf 但不知何故我不知道该怎么做 我搜索了 stackoverflow 并已经阅读了有关 nbconvert 的内容 但是我在哪里输入该命令 在笔记本里 在cmd提示符下 如果有人可以一步一步告
  • IPython 笔记本 - 无法导出为 pdf

    我正在尝试将 IPython 笔记本导出为 pdf 但不知何故我不知道该怎么做 我搜索了 stackoverflow 并已经阅读了有关 nbconvert 的内容 但是我在哪里输入该命令 在笔记本里 在cmd提示符下 如果有人可以一步一步告
  • 如何以编程方式设置 CKEditor 的默认表属性?

    我正在尝试设置在 CKEditor 内创建的表的默认属性 例如 有没有办法确保属性边框为 0 而不是 1 或者宽度默认设置为 100 干得好 dialogDefinition事件解决了问题 CKEDITOR on dialogDefinit
  • 如何以编程方式设置 CKEditor 的默认表属性?

    我正在尝试设置在 CKEditor 内创建的表的默认属性 例如 有没有办法确保属性边框为 0 而不是 1 或者宽度默认设置为 100 干得好 dialogDefinition事件解决了问题 CKEDITOR on dialogDefinit
  • Application.ThreadException:如果不分离,内存泄漏?

    The 参考页 http msdn microsoft com en us library system windows forms application threadexception aspx对于 Application Thread
  • Application.ThreadException:如果不分离,内存泄漏?

    The 参考页 http msdn microsoft com en us library system windows forms application threadexception aspx对于 Application Thread
  • Java:多线程和UDP套接字编程

    我是 Java 多线程和套接字编程的新手 我想知道实现 2 个线程的最佳方法是什么 一个用于接收套接字 一个用于发送套接字 如果我想做的事情听起来很荒谬 请告诉我为什么 该代码很大程度上受到 Sun 在线教程的启发 我想使用多播套接字 以便
  • Java:多线程和UDP套接字编程

    我是 Java 多线程和套接字编程的新手 我想知道实现 2 个线程的最佳方法是什么 一个用于接收套接字 一个用于发送套接字 如果我想做的事情听起来很荒谬 请告诉我为什么 该代码很大程度上受到 Sun 在线教程的启发 我想使用多播套接字 以便
  • 使用 CSS 在图像上重叠文本

    我有一个图像 我想将底部的一段文本与透明的黑色背景重叠 实现这一目标的最简单方法是什么 img src http assets3 parliament uk iv main large ImageVault Images id 7382 s
  • 使用 CSS 在图像上重叠文本

    我有一个图像 我想将底部的一段文本与透明的黑色背景重叠 实现这一目标的最简单方法是什么 img src http assets3 parliament uk iv main large ImageVault Images id 7382 s
  • .NET 元组和等于性能

    这是我直到今天才注意到的事情 显然 常用的元组类的 NET 实现 Tuple
  • .NET 元组和等于性能

    这是我直到今天才注意到的事情 显然 常用的元组类的 NET 实现 Tuple