【问题标题】:Is there any very rapid checksum generation algorithm?有没有非常快速的校验和生成算法?
【发布时间】:2012-04-26 14:09:29
【问题描述】:

搜索了一下,但我并没有真正找到我要找的东西。

我必须每秒验证大约 100 字节[16384](+许多其他任务..)。眼下最大的问题是速度。

你们知道 C#.NET 中有什么好的校验和算法非常快吗?它不必非常精确,但如果单个位发生变化,校验和也应该(通常..)发生变化。

字节存储在内存中,因此没有 IO 东西会减慢它的速度。

谢谢!

【问题讨论】:

  • 大多数校验和都需要遍历每个字节,这确实是缓慢的部分。对每个字节执行的操作往往不是特别昂贵。如果您有真正的顾虑,请尝试实现几种算法并分析它们以查看哪个最快,以及它是否对您来说足够快。
  • 每个字节数组都以许多空字节结尾,但有些则没有。这些是否也会减慢速度,还是有一些快速的方法可以去除它们?
  • 看看crc-32
  • @Tgys 多少是“很多”。对一个人来说很多,对于一台计算机来说通常很多。
  • 空值很重要,对吧?您希望校验和根据它们的数量而有所不同。

标签: c# .net performance hash checksum


【解决方案1】:

扩展 C.Evenhuis 的答案,这里有一些变化应该会更快一些。我不确定他们的正确性,有更多经验的人想帮助我吗?我知道他们给出的校验和与每字节的校验和不同,但我确实认为他们给出的校验和与每字节的校验和一样 good (不是很好,但显然足够)。

正如我在评论中所说,您可以通过不逐字节比较,而是将数组视为小 4 倍的整数数组或小 8 倍的长数组来提高速度。不过,将其视为long[] 只会在 64 位上提供性能优势。

static unsafe uint ChecksumInt(byte[] array)
{
  unchecked
  {
    uint checksum = 0;
    fixed (byte* ptr = array)
    {
      var intPtr = (uint*)ptr;

      var iterations = array.Length / 4;
      var remainderIterations = array.Length % 4;

      for (var i = 0; i < iterations; i++)
      {
        var val = intPtr[i];
        checksum += val;
      }

      while (remainderIterations >= 0) // no more than 3 iterations
      {
        checksum += ptr[array.Length - remainderIterations];
        remainderIterations--;
      }
      return checksum;
    }
  }
}

static unsafe ulong ChecksumLong(byte[] array)
{
  unchecked
  {
    ulong checksum = 0;
    fixed (byte* ptr = array)
    {
      var intPtr = (ulong*)ptr;

      var iterations = array.Length / 8;
      var remainderIterations = array.Length % 8;

      for (var i = 0; i < iterations; i++)
      {
        var val = intPtr[i];
        checksum += val;
      }

      while (remainderIterations >= 0) // no more than 7 iterations
      {
        checksum += ptr[array.Length - remainderIterations];
        remainderIterations--;
      }
      return checksum;
    }
  }
}

我在 64 位(Core 2 Duo 3 GHz)上对包含 100,000 个项目的数组进行了 10,000 次迭代的性能测量:

  • 每 1 个字节:00:00:00.7052533
  • 每 4 个字节:00:00:00.1761491
  • 每 8 个字节:00:00:00.0856880

所以相当快。

但是,就像我说的,我不确定这是否提供了同样好的校验和。

【讨论】:

    【解决方案2】:

    如果每一个比特都很重要,那么校验和算法就必须处理每一个字节。一个简单的算法就是简单地将每个值相加并忽略溢出:

        static unsafe uint GetChecksum(byte[] array)
        {
            unchecked
            {
                uint checksum = 0;
                fixed (byte* arrayBase = array)
                {
                    byte* arrayPointer = arrayBase;
                    for (int i = array.Length - 1; i >= 0; i--)
                    {
                        checksum += *arrayPointer;
                        arrayPointer++;
                    }
                }
                return checksum;
            }
        }
    

    当然,您可能无法检测到所有更改并获得重复项,但它可能会为您提供有关快速算法执行情况的指示。

    【讨论】:

    • 其实是个聪明的主意,到目前为止它似乎运行得足够快。我现在再做一些测试。
    • 您应该能够通过将 byte* 视为 int* 来大大加快速度,这将使您每次循环求和 4 个字节而不是 1。我会尝试添加代码当我有时间。
    猜你喜欢
    • 2010-09-12
    • 1970-01-01
    • 2011-02-23
    • 2017-08-13
    • 2015-08-16
    • 1970-01-01
    • 1970-01-01
    • 2018-07-30
    相关资源
    最近更新 更多