.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 控件
  • 小数可以表示的第二个最小值是多少?

    什么是第二个最小值值一个decimal可以代表吗 该值大于Decimal MinValue并且小于任何其他值decimal可以代表 在C 中如何获取这个值 谢谢 第二个最小值是Decimal MinValue 1 这可以从文档中推断出dec
  • C#计算面积和周长[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 所以我使用 Microsoft Vi
  • 如何将程序集保存到磁盘?

    如何将程序集保存到文件 IE 我的意思不是动态程序集 而是 正常 内存中程序集 Assembly asslist AppDomain CurrentDomain GetAssemblies foreach Assembly ass1 in
  • 正在更改的线程参数

    当启动多个线程时 id我正在解析的参数有时是错误的 这是我的启动 for int i 0 i lt threadCount i Thread thread new Thread gt WorkerThread i thread Start
  • 正在更改的线程参数

    当启动多个线程时 id我正在解析的参数有时是错误的 这是我的启动 for int i 0 i lt threadCount i Thread thread new Thread gt WorkerThread i thread Start
  • 在 vb.net 中打乱字符串数组

    我正在 vb net 中开发一个网页 它将向用户生成许多多项选择题 我需要对已经放入数组中的四个答案进行洗牌 假设我必须遵循以下数组 array Correct Wrong1 Wrong2 Wrong3 我尝试使用以下方法 Public S
  • 添加 jQuery 监听器会降低浏览器性能吗?

    我有一个应用程序 它通过 Ajax 带来响应 并在每次刷新时创建 5 20 个新的 jQuery 单击侦听器 IE 和 Mozilla 浏览器的使用速度似乎都在变慢 这会显着降低浏览器性能吗 听众能被 释放 吗 补充一下安迪关于现场的说法
  • Neuroph 神经网络帮助

    在我的研究生研究中 我正在创建一个训练识别图像的神经网络 我要做的事情比像许多示例那样仅采用 RGB 值网格 下采样并将它们发送到网络的输入要复杂得多 实际上 我使用了 100 多个独立训练的神经网络来检测线条 阴影图案等特征 更像人眼 而
  • 远程控制内网机器上安装的windows服务

    我在本地 IIS 7 上部署了 Web 应用程序 并将应用程序池配置为在内置 NETWORK SERVICE 帐户下工作 我需要从这个 Web 应用程序检查 Windows 服务的状态 是否已启动 已停止等 我用这样的语句来得到它 publ
  • dotnet sdk 已安装但无法识别 - Linux Ubuntu/popOS 22.04

    昨天我的 dotnet sdk 工作得很好 今天当我登录到我的电脑时 我更新了系统和 VSCode 然后当我尝试运行时dotnet watch run 我收到此错误 You intended to execute a NET applica
  • 使用参数的 SQL Server 查询比使用常量字符串的查询花费的时间更长

    我在使用 MS SQL Server 2008 时遇到一个问题 当我使用硬编码字符串作为参数执行查询时 查询运行得很快 但是当我使用字符串参数时 查询需要更长的时间 常量字符串查询需要1秒 而其他则需要11秒 以下是代码 常量字符串 1秒
  • 我的标准差计算可以更加高效吗?

    我很好奇我的标准差方法是否可以变得更有效 我所说的高效是指快速 而快速是指从方法调用到方法返回的延迟 这是代码 public double stdDev ArrayList
  • 当 ObservableCollection 更改时重新评估 LINQ 查询

    我有一个常见问题 我希望 希望 找到更好的解决方案来继续前进 我有一个包含数据主列表的 ObservableCollection 在我的客户端代码中 我需要将数据 转换 为新的形式以显示给用户 我使用如下 LINQ 语句 var newLi
  • .NET 4 代码契约:“需要未经验证:源!= null”

    我刚刚开始在我的项目中使用代码契约 但是 我的存储库实现存在问题 它使用实体框架查询数据库 我有以下方法 public IEnumerable
  • 如何使文本框的自动完成列表可编辑?

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

    我在这里阅读了很多有关可用工具的问答unusedJAR 例如 loosejar http code google com p loosejar 类路径助手 http classpathhelper sourceforge net 我的问题是
  • 如何通过可变参数模板表达概念?

    我想定义一个概念 只有具有特定类型值的元组才能满足 假设为了简单起见 我只想接受仅包含数字类型元素的元组 我该怎么做 e g std tuple
  • 如何调节日志指令随时间产生的打印输出量?

    如何将程序日志打印输出限制为 Y 秒内最多 X 个打印输出 使用 java util logging 进行服务器端编程 我的代码有很多信息 警告和错误语句 例如 s logger logp Level WARNING myClassName
  • 如何在cmd / powershell中运行Nuget Package Manager Host

    我目前正在使用更新包Visual Studio 2017 Nuget 包管理器控制台中的命令 我需要从命令提示符使用它 eg nuget Update Package Newtonsoft Json Visual Studio 的包管理器控

随机推荐

  • Rotativa 和 wkhtmltopdf 在 iis6 上通过 HTTPS 没有 CSS 或图像,但在 HTTP 上正常

    使用 Rotativa wkhtmltopdf 的 net 包装器 如果我通过 HTTPS 连接 则无法在 PDF 中渲染 CSS 或图像 我之前已经在 2008r2 iis7 服务器上使用 HTTPS SSL 设置了这个 我确实在 css
  • 处理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