为什么C++fseek/fread的性能是C#FileStream的数倍;s搜索/读取

本文关键字:搜索 读取 C++fseek fread 性能 为什么 C#FileStream | 更新日期: 2023-09-27 18:00:08

我正在做一个非常简单的测试:

  1. 拥有一个包含随机二进制信息的大文件,大小约为6Gb
  2. 算法使"SeekCount"重复循环
  3. 每次重复都要执行以下操作:
    • 计算文件大小范围内的随机偏移
    • 寻找那个偏移
    • 读取小块数据

C#:

    public static void Test()
    {
        string fileName = @"c:'Test'big_data.dat";
        int NumberOfSeeks = 1000;
        int MaxNumberOfBytes = 1;
        long fileLength = new FileInfo(fileName).Length;
        FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read, 65536, FileOptions.RandomAccess);
        Console.WriteLine("Processing file '"{0}'"", fileName);
        Random random = new Random();
        DateTime start = DateTime.Now;
        byte[] byteArray = new byte[MaxNumberOfBytes];
        for (int index = 0; index < NumberOfSeeks; ++index)
        {
            long offset = (long)(random.NextDouble() * (fileLength - MaxNumberOfBytes - 2));
            stream.Seek(offset, SeekOrigin.Begin);
            stream.Read(byteArray, 0, MaxNumberOfBytes);
        }
        Console.WriteLine(
            "Total processing time time {0} ms, speed {1} seeks/sec'r'n",
            DateTime.Now.Subtract(start).TotalMilliseconds, NumberOfSeeks / (DateTime.Now.Subtract(start).TotalMilliseconds / 1000.0));
        stream.Close();
    }

然后在C++中进行相同的测试:

void test()
{
     FILE* file = fopen("c:''Test''big_data.dat", "rb");
char buf = 0;
__int64 fileSize = 6216672671;//ftell(file);
__int64 pos;
DWORD dwStart = GetTickCount();
for (int i = 0; i < kTimes; ++i)
{
    pos = (rand() % 100) * 0.01 * fileSize;
    _fseeki64(file, pos, SEEK_SET);
    fread((void*)&buf, 1 , 1,file);
}
DWORD dwEnd = GetTickCount() - dwStart;
printf(" - Raw Reading: %d times reading took %d ticks, e.g %d sec. Speed: %d items/sec'n", kTimes, dwEnd, dwEnd / CLOCKS_PER_SEC, kTimes / (dwEnd / CLOCKS_PER_SEC));
fclose(file);
}

执行次数:

  1. C#:100-200次读取/秒
  2. C++:250 000次读取/秒(25万次)

问题:为什么C++在文件读取这样一个琐碎的操作上比C#快数千倍?

附加信息:

  1. 我玩了流缓冲区,并将它们设置为相同大小(4Kb)
  2. 磁盘已去碎片化(0%碎片)
  3. 操作系统配置:Windows 7、NTFS、一些最新的现代500Gb HDD(WD,如果回忆正确的话)、8GB RAM(尽管几乎没有使用)、4核CPU(利用率几乎为零)

为什么C++fseek/fread的性能是C#FileStream的数倍;s搜索/读取

C++版本的测试中有一个错误-随机偏移的计算受到限制,因此只能在短距离内进行搜索,这使得C++结果看起来更好。

@MooingDuck:建议计算偏移量的正确代码

rand()/double(rand_MAX)*文件大小

随着这种变化,C++和C#的性能变得相当——大约200次读取/秒。

感谢大家的贡献。