生成大量哈希
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 是不可能达到那个速度的。
但是,您可以通过以下几项操作来获得一些性能:
- 您可以利用
Parallel.For
的 localInit 创建 SHA256 对象,以及一个大小为 8 的字节数组来保存要散列的数据,每个任务一次。
- 不需要显式调用
Initialize
。
- 您可以使用指针或
Unsafe
class 一次设置所有字节,而不是手动将 long 转换为字节数组,一次一个字节。
- 预先分配将保存散列的字节数组,并使用
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()
);
我想生成大量 (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 是不可能达到那个速度的。 但是,您可以通过以下几项操作来获得一些性能:
- 您可以利用
Parallel.For
的 localInit 创建 SHA256 对象,以及一个大小为 8 的字节数组来保存要散列的数据,每个任务一次。 - 不需要显式调用
Initialize
。 - 您可以使用指针或
Unsafe
class 一次设置所有字节,而不是手动将 long 转换为字节数组,一次一个字节。 - 预先分配将保存散列的字节数组,并使用
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()
);