生成大量哈希

Generating huge amount of hashes

我想生成大量 (10 TB) 看似随机但可预测的数字。生成速度应该超过快速SSD,所以我想要3000MB/s到4000MB/s。

文件写入后,会再次读取数字,重新生成,以便进行比较。整个程序应该检查磁盘。

目前我正在考虑哈希。为了可预测性,要散列的数据只是一个 8 字节的数字 (ulong)。所以在二进制文件中它看起来像这样

<32 bytes of SHA256(0)> <32 bytes of SHA256(1)> ...

我认为我不能使用带有种子的随机数生成器,因为我无法告诉随机数生成器生成第 n 个数字。但是我可以告诉SHA256算法计算SHA256(n)。

我使用 SHA256 算法对 128 MB 数据进行了测试,如下所示:

Parallel.For(0, 128 * 1024 * 1024 / 32,     // 128 MB / length of the hash
    a => {
        var sha = SHA256.Create();
        sha.Initialize();
        var ba = new byte[8];
        ba[0] = (byte)((long)a >> 0 & 0xFF);
        ba[1] = (byte)((long)a >> 8 & 0xFF);
        ba[2] = (byte)((long)a >> 16 & 0xFF);
        ba[3] = (byte)((long)a >> 24 & 0xFF);
        ba[4] = (byte)((long)a >> 32 & 0xFF);
        ba[5] = (byte)((long)a >> 40 & 0xFF);
        ba[6] = (byte)((long)a >> 48 & 0xFF);
        ba[7] = (byte)((long)a >> 56 & 0xFF);
        var hash = sha.ComputeHash(ba);
        // TODO: aggregate the byte[]s, stream to file
    }
);

像这样,我的 Ryzen 7 2700X 8 核处理器 运行 在 4.08 GHz 时的吞吐量仅为 95 MB/s。

是否有可能将其加速到 4000 MB/s?

我认为不使用 gpu 是不可能达到那个速度的。 但是,您可以通过以下几项操作来获得一些性能:

  1. 您可以利用 Parallel.For 的 localInit 创建 SHA256 对象,以及一个大小为 8 的字节数组来保存要散列的数据,每个任务一次。
  2. 不需要显式调用Initialize
  3. 您可以使用指针或 Unsafe class 一次设置所有字节,而不是手动将 long 转换为字节数组,一次一个字节。
  4. 预先分配将保存散列的字节数组,并使用 TryComputeHash 而不是 ComputeHash,因为它允许为输出传递跨度。

这是实现上述内容的代码:

Parallel.For(0, 128 * 1024 * 1024 / 32,     // 128 MB / length of the hash
  () => (SHA256.Create(), new byte[8], new byte[32]),
  (a, state, tuple) =>
  {
    Unsafe.As<byte, long>(ref tuple.Item2[0]) = a;
    tuple.Item1.TryComputeHash(tuple.Item2, tuple.Item3, out _);
    var hash = tuple.Item3;
    // TODO: aggregate the byte[]s, stream to file
    return tuple;
  },
  tuple => tuple.Item1.Dispose()
);