有没有更快的方法来使用 FileStream 读取数据?
Is there a faster way to read data with a FileStream?
所以我尝试尽可能快地读取数据并将其存储在数组中,我发现最快的方法是这样做。
var filePath = "data.dat";
FileStream fs = new FileStream(filePath, FileMode.Open);
bool[] buffer = new bool[fs.Length];
TimeSpan[] times = new TimeSpan[500000];
Stopwatch sw = new Stopwatch();
for (int r = 0; r < 500000; r++)
{
sw.Start();
int stackable = 0;
int counter = 0;
while ((stackable = fs.ReadByte()) != -1)
{
buffer[counter] = (stackable == 1);
counter++;
}
sw.Stop();
Console.WriteLine($"Elapsed: {sw.Elapsed}ms");
times[r] = sw.Elapsed;
sw.Reset();
}
Console.WriteLine($"Longest itteration: {times.Max()}ms");
它设法在 < 3 毫秒内读取和处理大约 9000 个字节。
这个想法是检查每个字节以查看它是 1 还是 0(真或假)并将其存储在数组中。
所以我的问题是,有没有更快的方法来实现这个目标?尝试快速处理数据时要记住哪些事项,是否要确保您使用的是较小的数据类型,以免分配不必要的内存?
数据是什么样的。
好吧,我们正在使用缓冲 IO,因此按字节迭代并不 不好。
但是,一次(如果可以的话)将数据读入缓冲区总是更快——一次 IO。
所以在下面我使用了你的代码 - 必须在循环中添加一个 seek(0) 来重置迭代。
在下一个块中,我读取了所有数据并使用新的 .AsSpan<>() 进行迭代 - 这是迭代数组的新快速方法。
using System;
using System.Diagnostics;
using System.IO;
namespace test_con
{
class Program
{
static void Main(string[] args)
{
makedata();
var filePath = "data.dat";
var loop_cnt = 5000;
using FileStream fs = new FileStream(filePath, FileMode.Open);
bool[] buffer = new bool[fs.Length];
Stopwatch sw = new Stopwatch();
sw.Start();
for (int r = 0; r < loop_cnt; r++)
{
int stackable = 0;
int counter = 0;
while ((stackable = fs.ReadByte()) != -1)
{
buffer[counter] = (stackable == 1);
counter++;
}
fs.Seek(0, SeekOrigin.Begin);
}
Console.WriteLine($"avg iteration: {sw.Elapsed.TotalMilliseconds/loop_cnt}");
var byte_buf = new byte[fs.Length];
sw.Restart();
for (int r = 0; r < loop_cnt; r++)
{
fs.Seek(0, SeekOrigin.Begin);
fs.Read(byte_buf);
int counter = 0;
foreach(var b in byte_buf.AsSpan()) {
buffer[counter] = (b == 1);
counter++;
}
}
Console.WriteLine($"buf avg iteration: {sw.Elapsed.TotalMilliseconds / loop_cnt}");
}
static void makedata()
{
var filePath = "data.dat";
if (!File.Exists(filePath))
{
Random rnd = new Random();
using FileStream fs = new FileStream(filePath, FileMode.CreateNew);
for (int n = 0; n < 100000; n++)
{
if (rnd.Next() % 1 == 1)
fs.WriteByte(0);
else
fs.WriteByte(1);
}
}
}
}
}
我的 2012 MacBook 上的输出是:
avg iteration: 1.01832286
buf avg iteration: 0.6913623999999999
所以缓冲区迭代只有流迭代的 70% 左右。
所以我尝试尽可能快地读取数据并将其存储在数组中,我发现最快的方法是这样做。
var filePath = "data.dat";
FileStream fs = new FileStream(filePath, FileMode.Open);
bool[] buffer = new bool[fs.Length];
TimeSpan[] times = new TimeSpan[500000];
Stopwatch sw = new Stopwatch();
for (int r = 0; r < 500000; r++)
{
sw.Start();
int stackable = 0;
int counter = 0;
while ((stackable = fs.ReadByte()) != -1)
{
buffer[counter] = (stackable == 1);
counter++;
}
sw.Stop();
Console.WriteLine($"Elapsed: {sw.Elapsed}ms");
times[r] = sw.Elapsed;
sw.Reset();
}
Console.WriteLine($"Longest itteration: {times.Max()}ms");
它设法在 < 3 毫秒内读取和处理大约 9000 个字节。 这个想法是检查每个字节以查看它是 1 还是 0(真或假)并将其存储在数组中。
所以我的问题是,有没有更快的方法来实现这个目标?尝试快速处理数据时要记住哪些事项,是否要确保您使用的是较小的数据类型,以免分配不必要的内存?
数据是什么样的。
好吧,我们正在使用缓冲 IO,因此按字节迭代并不 不好。 但是,一次(如果可以的话)将数据读入缓冲区总是更快——一次 IO。 所以在下面我使用了你的代码 - 必须在循环中添加一个 seek(0) 来重置迭代。
在下一个块中,我读取了所有数据并使用新的 .AsSpan<>() 进行迭代 - 这是迭代数组的新快速方法。
using System;
using System.Diagnostics;
using System.IO;
namespace test_con
{
class Program
{
static void Main(string[] args)
{
makedata();
var filePath = "data.dat";
var loop_cnt = 5000;
using FileStream fs = new FileStream(filePath, FileMode.Open);
bool[] buffer = new bool[fs.Length];
Stopwatch sw = new Stopwatch();
sw.Start();
for (int r = 0; r < loop_cnt; r++)
{
int stackable = 0;
int counter = 0;
while ((stackable = fs.ReadByte()) != -1)
{
buffer[counter] = (stackable == 1);
counter++;
}
fs.Seek(0, SeekOrigin.Begin);
}
Console.WriteLine($"avg iteration: {sw.Elapsed.TotalMilliseconds/loop_cnt}");
var byte_buf = new byte[fs.Length];
sw.Restart();
for (int r = 0; r < loop_cnt; r++)
{
fs.Seek(0, SeekOrigin.Begin);
fs.Read(byte_buf);
int counter = 0;
foreach(var b in byte_buf.AsSpan()) {
buffer[counter] = (b == 1);
counter++;
}
}
Console.WriteLine($"buf avg iteration: {sw.Elapsed.TotalMilliseconds / loop_cnt}");
}
static void makedata()
{
var filePath = "data.dat";
if (!File.Exists(filePath))
{
Random rnd = new Random();
using FileStream fs = new FileStream(filePath, FileMode.CreateNew);
for (int n = 0; n < 100000; n++)
{
if (rnd.Next() % 1 == 1)
fs.WriteByte(0);
else
fs.WriteByte(1);
}
}
}
}
}
我的 2012 MacBook 上的输出是:
avg iteration: 1.01832286
buf avg iteration: 0.6913623999999999
所以缓冲区迭代只有流迭代的 70% 左右。