【问题标题】:Significant performance difference within integers of different bits for small numbers小数的不同位整数内的显着性能差异
【发布时间】:2012-07-28 15:13:12
【问题描述】:

我将第一次使用非常少量的非常小的数字(因为每个 int 将在 1 到 10 之间,并且一次有 100 个这样的变量),我想知道是否有使用 16 位整数与 32 位的任何显着性能差异。我的大多数用户将使用 64 位处理器,但有些用户将使用 32 位。

【问题讨论】:

  • 听起来像是过早优化的情况。是什么让您认为这些变量将成为您的应用程序中性能问题的最大来源?例如,向数据库发送网络请求可能比分配 1000 个元素的数组长 100 倍。
  • 你将如何处理这些数字?
  • 一般来说,与处理器的本机整数大小匹配的整数(32 位 CPU 上为 32 位,64 位 CPU 上为 64 位)执行速度最快。但是,这不是不进行测试和基准测试的借口——除了 CPU 处理整数的速度之外,可能还有其他因素,例如交换、缓存未命中等。
  • 100 个变量对于任何现代计算机来说都不是一个大数目。在达到数十万或数百万个数字之前,您可能看不到任何显着差异。
  • mellamokb,绝对不会,但我想减少哪怕是最小的一点。 Thomas Levesque,它们很少更改(可能其中一些更改每 20 秒左右),但会不断访问。 cdhowie,我知道这一点,但我想知道如果还有其他需要考虑的数字是否会如此之小。 Anders Abel,好点子,但如果这会改变任何事情,它们将很快被使用(如“if”语句等)

标签: c# performance variables integer


【解决方案1】:

CPU

在处理单个数字时,可能使用更紧凑的表示会略有改进。也就是说,

ushort a;
ushort b;

// @mikez pointed a & b are  promoted to int when added
// C# spec, 7.3.6.2 Binary numeric promotions
ushort result = (ushort)(a + b); 

可能略快于

ulong a;
ulong b;

ulong result = a + b;

取决于您的算法。原因是当单个数字较小时,更多的数据可以放入 CPU 缓存中,最终需要从 RAM 传输到 CPU 的数据更少。

另一方面,由于读取/写入未与 64 位地址边界对齐的数据,它可能会稍慢

这两个因素相互影响。衡量您的用例,以从 CPU 的角度了解您的情况是好是坏。

在内存中

使用 List<ushort> 而不是 List<ulong> 将节省 75% 的内存成本。 如果这会阻止交换,它将使您的应用程序受益。

在磁盘上

如果您要保存到数据库,并且如果您的工作集太大而无法容纳数据库引擎可用的 RAM,则使用较小的大小可能会对性能产生巨大的影响,因为更多的记录适合较少的磁盘扇区减少磁盘寻道时间(假设没有 SSD)并增加单位时间内可通过 IO 通道传输的数据点数量。

警告

请注意,所有这些数量非常大与您计算机的处理能力相比是真实的情况下才重要。如果您有足够的 RAM 将所有数据保存在内存中,则不会交换。如果您的数据库服务器和/或存储控制器缓存可以将您的工作集保存在内存中,那么磁盘存储大小的考虑就无关紧要了。

底线

如果您对要处理的值的范围有误,那么使用较小的数据类型只会对您造成伤害,并且您突然需要较大的数据类型来保存所有值。

快速制作关键算法的原型。使用各种 ushort、uint、ulong 选项执行一些测量。

如果您的“100 个变量”每个都只包含一个数字(而不是一个包含大量数字的列表),那么这些都不重要。只有当您开始对您的计算机施加压力时(可能在 10 到 100 的数百万个数据点或更多,具体取决于您在做什么),这些优化才会真正对您的用户产生影响。

【讨论】:

  • +1。不错的总结。考虑添加“首先测量”是理想的:)。我会将 CPU 投入更多“可能会因读/写不对齐而提高或可能降低性能”。
  • 感谢您的出色回答,但还有一个问题,如果在特定情况下使用较小的值确实会增加性能,那么将整数转换为较大的整数以供临时使用平衡它甚至损害性能?
  • @AlexeiLevenkov:是的,我把它加进去了。每次都在研究答案。
  • @leaf68:这取决于。如果您说您通常要处理 10 亿个值,并且需要将其中的 1,000 个转换为更大的类型以进行一些处理,可能您肯定会在需要时保持较小的值。如果数字不同,我建议您运行一些模拟并测量您的用例。
  • 实际上第一个示例甚至无法编译,因为没有为ushort 定义+。现代处理器针对 32 位和 64 位操作进行了大量优化,实际上并没有针对较小表示(16 位或 8 位)的内置操作。我猜框架试图通过不定义算术运算符来告诉我们“不要用这些做数学,因为它效率不高”。
【解决方案2】:

如有疑问,请测量。但除了内存消耗差异之外,我怀疑你会看到任何东西。

【讨论】:

    【解决方案3】:

    这里的答案总体上很好,但是在 .NET 平台上有一个特定的考虑:CIL 中没有 8 位或 16 位算术运算。

    这意味着所有 8 位和 16 位值都被隐式转换为 32 位以进行算术运算。

    ECMA Specs - Part 3 (CIL) - 第 1.6 节隐式参数强制

    【讨论】:

    • hmm...有没有办法解决这个问题,以便它在本机上运行 16 位数字?
    • 执行单个操作的互操作开销从性能角度来看是可怕的。在做任何事情之前,我也会衡量它的影响。我不怀疑这会对应用程序的总性能成本产生很大影响。
    • @EricJ。是的,如果您要进行互操作,您会希望在大型“夹盘”中进行(即在本机执行整个操作)。
    猜你喜欢
    • 1970-01-01
    • 2019-01-23
    • 2013-01-09
    • 2021-05-05
    • 2020-10-03
    • 2015-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多