【问题标题】:Why performance of C++ fseek/fread is times greater than C# FileStream's Seek/Read为什么 C++ fseek/fread 的性能是 C# FileStream 的 Seek/Read 的几倍
【发布时间】:2013-02-20 02:37:02
【问题描述】:

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

  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++:25 万次读取/秒(25 万次)

问题:为什么在文件读取这样微不足道的操作上,C++ 比 C# 快数千倍?

其他信息:

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

【问题讨论】:

  • 那不是 C++,那是 C。
  • 还有,MaxNumberOfBytes的值是多少?
  • @Öö Tiib:这可能是您的经验,但该因素对上下文非常敏感。在任何情况下,OP 都声称存在数量级的差异,这一定意味着他正在以某种方式将苹果与橙子进行比较。
  • (rand()%100)*0.01 似乎很可疑——实际上你只是在读取文件的 100 个偏移量之一,这可能会利用底层缓存机制,因此并没有真正从磁盘读取块。尝试使用 rand() % fileSize 之类的东西,使代码更符合 C# 版本。
  • @David:你错过了他的意思,C++ 代码只会从随机选择的 100 个位置读取,而 Java 会从所有位置读取,这不公平。对于 C++,将其更改为 rand()/double(RAND_MAX)*fileSize 以具有与 Java 相同的功能

标签: c# c++ performance filestream


【解决方案1】:

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

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

rand()/double(RAND_MAX)*fileSize

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

感谢大家的贡献。

【讨论】:

    猜你喜欢
    • 2012-02-11
    • 2017-07-07
    • 1970-01-01
    • 2011-03-20
    • 1970-01-01
    • 2021-07-21
    • 2018-11-20
    • 2015-05-20
    • 1970-01-01
    相关资源
    最近更新 更多