高效地将 int 数组写入文件
Efficiently writing an int array to file
我有一个可能更大的 int
数组,我正在使用 BinaryWriter
写入文件。当然,我可以使用默认的方式。
using (BinaryWriter writer = new BinaryWriter(File.Open(path, FileMode.Create)))
{
writer.Write(myIntArray.Length);
foreach (int value in myIntArray)
writer.Write(value);
}
但这似乎非常低效。我很确定 int
数组在内存中连续存储数据。有没有办法像使用 byte
数组那样将内存直接写入文件?也许是一种将 int
数组转换(而不是复制)到 byte
数组的方法?
通过 MemoryMarshal.Cast 和 Span<T>
支持最有效的形式,无需在 .NET Core 中进行任何复制。这直接重新解释了内存,但这可能无法跨平台移植,因此应谨慎使用:
int[] values = { 1, 2, 3 };
using (var writer = new BinaryWriter(File.Open(path, FileMode.Create)))
{
Span<byte> bytes = MemoryMarshal.Cast<int, byte>(values.AsSpan());
writer.Write(bytes);
}
此 API 从 MemoryExtensions.NonPortableCast
移动时的一些相关讨论
但是我会说你的原版实际上会相当有效,因为 BinaryWriter 和 FileStream 都有自己的内部缓冲区,在编写这样的整数时会使用这些缓冲区。
我认为对上面列出的每个方法进行基准测试会很有趣,原始方法来自@Jonathan-Wood (TestCopyStream),来自@Mike-Zboray (TestCopySpan) 的 Span 建议和 Buffer BlockCopy来自@oleg-bondarenko (TestCopySpanByteCopy) [是的,命名很难]。
我正在生成大小为 N 的随机数 int 数组,每个 运行 的集合相同。
结果如下:
| Method | N | Mean | Error | StdDev | Median | Ratio | RatioSD | Rank | Gen 0 | Gen 1 | Gen 2 | Allocated |
|--------------------- |------ |---------:|----------:|----------:|---------:|------:|--------:|-----:|--------:|------:|------:|----------:|
| TestCopySpan | 1000 | 1.372 ms | 0.0382 ms | 0.1109 ms | 1.348 ms | 1.00 | 0.11 | 1 | - | - | - | 4984 B |
| TestCopyStream | 1000 | 1.377 ms | 0.0324 ms | 0.0935 ms | 1.364 ms | 1.00 | 0.00 | 1 | - | - | - | 4984 B |
| TestCopySpanByteCopy | 1000 | 2.215 ms | 0.0700 ms | 0.2008 ms | 2.111 ms | 1.62 | 0.19 | 2 | 3.9063 | - | - | 13424 B |
| | | | | | | | | | | | | |
| TestCopySpan | 10000 | 1.617 ms | 0.1167 ms | 0.3155 ms | 1.547 ms | 0.80 | 0.19 | 1 | - | - | - | 864 B |
| TestCopyStream | 10000 | 2.032 ms | 0.0776 ms | 0.2251 ms | 1.967 ms | 1.00 | 0.00 | 2 | - | - | - | 4984 B |
| TestCopySpanByteCopy | 10000 | 2.433 ms | 0.0703 ms | 0.2040 ms | 2.430 ms | 1.21 | 0.18 | 3 | 11.7188 | - | - | 45304 B |
我有一个可能更大的 int
数组,我正在使用 BinaryWriter
写入文件。当然,我可以使用默认的方式。
using (BinaryWriter writer = new BinaryWriter(File.Open(path, FileMode.Create)))
{
writer.Write(myIntArray.Length);
foreach (int value in myIntArray)
writer.Write(value);
}
但这似乎非常低效。我很确定 int
数组在内存中连续存储数据。有没有办法像使用 byte
数组那样将内存直接写入文件?也许是一种将 int
数组转换(而不是复制)到 byte
数组的方法?
通过 MemoryMarshal.Cast 和 Span<T>
支持最有效的形式,无需在 .NET Core 中进行任何复制。这直接重新解释了内存,但这可能无法跨平台移植,因此应谨慎使用:
int[] values = { 1, 2, 3 };
using (var writer = new BinaryWriter(File.Open(path, FileMode.Create)))
{
Span<byte> bytes = MemoryMarshal.Cast<int, byte>(values.AsSpan());
writer.Write(bytes);
}
此 API 从 MemoryExtensions.NonPortableCast
但是我会说你的原版实际上会相当有效,因为 BinaryWriter 和 FileStream 都有自己的内部缓冲区,在编写这样的整数时会使用这些缓冲区。
我认为对上面列出的每个方法进行基准测试会很有趣,原始方法来自@Jonathan-Wood (TestCopyStream),来自@Mike-Zboray (TestCopySpan) 的 Span 建议和 Buffer BlockCopy来自@oleg-bondarenko (TestCopySpanByteCopy) [是的,命名很难]。
我正在生成大小为 N 的随机数 int 数组,每个 运行 的集合相同。
结果如下:
| Method | N | Mean | Error | StdDev | Median | Ratio | RatioSD | Rank | Gen 0 | Gen 1 | Gen 2 | Allocated |
|--------------------- |------ |---------:|----------:|----------:|---------:|------:|--------:|-----:|--------:|------:|------:|----------:|
| TestCopySpan | 1000 | 1.372 ms | 0.0382 ms | 0.1109 ms | 1.348 ms | 1.00 | 0.11 | 1 | - | - | - | 4984 B |
| TestCopyStream | 1000 | 1.377 ms | 0.0324 ms | 0.0935 ms | 1.364 ms | 1.00 | 0.00 | 1 | - | - | - | 4984 B |
| TestCopySpanByteCopy | 1000 | 2.215 ms | 0.0700 ms | 0.2008 ms | 2.111 ms | 1.62 | 0.19 | 2 | 3.9063 | - | - | 13424 B |
| | | | | | | | | | | | | |
| TestCopySpan | 10000 | 1.617 ms | 0.1167 ms | 0.3155 ms | 1.547 ms | 0.80 | 0.19 | 1 | - | - | - | 864 B |
| TestCopyStream | 10000 | 2.032 ms | 0.0776 ms | 0.2251 ms | 1.967 ms | 1.00 | 0.00 | 2 | - | - | - | 4984 B |
| TestCopySpanByteCopy | 10000 | 2.433 ms | 0.0703 ms | 0.2040 ms | 2.430 ms | 1.21 | 0.18 | 3 | 11.7188 | - | - | 45304 B |