生成大量哈希值

Tho*_*ler 0 .net c# optimization hash performance

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

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

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

<32 bytes of SHA256(0)> <32 bytes of SHA256(1)> ...
Run Code Online (Sandbox Code Playgroud)

我不认为我可以使用带种子的随机数生成器,因为我无法告诉随机数生成器生成第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
    }
);
Run Code Online (Sandbox Code Playgroud)

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

有机会将其速度加快至 4000 MB/s 吗?

Soh*_*ndi 6

我认为如果不使用 GPU 就不可能达到这个速度。但您可以采取以下一些措施来获得一些性能:

  1. 您可以利用 localInitParallel.For创建 SHA256 对象,以及大小为 8 的字节数组来保存要散列的数据,每个任务一次。
  2. 无需显式调用Initialize.
  3. 您可以使用指针或类一次性Unsafe设置所有字节,而不是手动将 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()
);
Run Code Online (Sandbox Code Playgroud)