【问题标题】:Should C++ file read be slower than Ruby or C#?C++ 文件读取是否应该比 Ruby 或 C# 慢?
【发布时间】:2018-01-05 21:13:57
【问题描述】:

对 C++ 完全陌生。

我正在比较 C++、C# 和 Ruby 的各个方面,看看是否需要镜像库。目前,简单读取文件(更新后)。

在 VS 2017 中编译 C++ 和 C#。C++ 处于 release(x64) 模式(或至少编译然后运行)

这些库或多或少地读取一个文件并将行分成三行,这些行构成一个对象的成员,然后存储在一个数组成员中。

为了进行压力测试,我尝试了一个 380MB(7M 行)的大文件(更新后),现在与 C++ 和 Ruby 的性能相似,

纯粹读取文件,不做其他事情的表现如下:

Ruby: 7s
C#:   2.5s
C++:  500+s (stopped running after awhile, something's clearly wrong)
C++(release build x64): 7.5s

代码:

#Ruby
file = File.open "test_file.txt"
while !file.eof 
    line = file.readline
end

//C#
StreamReader file = new StreamReader("test_file.txt");
file.Open();
while((line = file.ReadLine()) != null){

}



//C++
#include "stdafx.h"
#include "string"
#include "iostream"
#include "ctime"
#include "fstream"
int main()
{
    std::ios::sync_with_stdio(false);
    std::ifstream file;
    file.open("c:/sandboxCPP/test_file.txt");
    std::string line;

    std::clock_t start;
    double duration;
    start = std::clock();
    while (std::getline(file, line)) {

    }
    duration = (std::clock() - start) / (double)CLOCKS_PER_SEC;
    std::cout << "\nDuration: " << duration;
    while (true) 
    {

    }
    return 0;
}

编辑:以下表现非常出色。 0.03s

vector<string> lines;
string tempString = str.str();
boost::split(lines, tempString, boost::is_any_of("\n"));
start = clock();
cout << "\nCount: " << lines.size();
int count = lines.size();
string s;
for (int i = 0; i < count; i++) {
    s =  lines[i];
} 

s = 关于我可能不知道提升在做什么的可能性。改变了性能。

在循环结束时使用随机记录的 cout 进行测试。

谢谢

【问题讨论】:

  • 您能否发布您的实际完整源代码。您提供的 c++ 代码不应编译(它缺少右括号)。
  • 看到这个(可能是重复的):stackoverflow.com/q/6820765/10077 坚持std::ios::sync_with_stdio(false); 看看它是否显着加速。
  • 不管减速的原因是什么,分析非发布版本是没有意义的。您实际上是在要求编译器生成更易于调试的输出,而不是在调试模式下快速输出,那么为什么要测量它呢?
  • 也请在 Release 模式下尝试并报告速度差异。
  • @CBusBus 如果我们有 full 文件会有所帮助。保存一个新文件,删除所有注释掉的代码,然后尝试编译并运行它。它应该有 #include &lt;iostream&gt;int main 等内容。

标签: c++ ifstream


【解决方案1】:

根据 cmets 和最初发布的代码(现已修复 [现已删除]),之前存在一个编码错误(i++ 缺失),导致 C++ 程序无法输出任何内容。这加上完整代码示例中的while(true) 循环将呈现与问题中所述一致的症状(即用户等待 500 秒后没有看到输出并强制终止程序)。这是因为它会在不输出任何内容的情况下完成读取文件并进入故意添加的无限循环。

对于 120 万个文件,修改后的完整源代码在大约 1.6 秒内正确完成(根据 cmets)。我对提高性能的建议如下:

  1. 确保您在发布模式(而非调试模式)下进行编译。鉴于用户已指定他们正在使用 Visual Studio 2017,我建议查看官方 Microsoft 文档 (https://msdn.microsoft.com/en-us/library/wx0123s5.aspx) 以获得详细说明。

  2. 为了更容易诊断问题,不要在程序末尾添加无限循环。而是从 powershell / (cmd) 运行可执行文件并确认它正确终止。

编辑:我还要补充:

  1. 为了获得准确的计时,您还需要考虑操作系统磁盘缓存。多次运行每个基准测试以“预热”磁盘缓存。

【讨论】:

  • 感谢您的建议。最后,我使用 boost::split 循环,对于 1.24M 行它减少到 0.03 秒。我已经接受了答案,因为调试编译模式是一个重大问题。
  • 没问题。很高兴它得到了解决。感谢您的接受。
【解决方案2】:

C++ 不会在你告诉它的那一刻自动编写所有内容。相反,它会缓冲数据,以便一次写入所有数据,这通常更快。要说“我现在真的很想写这个。”,你需要说类似std::cout &lt;&lt; std::flush (如果你使用std::endl 来结束你的行,它会自动这样做)。

通常你不需要这样做;当程序退出时,或者当您要求用户输入时,缓冲区会被刷新,或者类似的事情。但是,您的程序不会退出,因此它永远不会刷新其缓冲区。你读取输入,然后程序永远执行while(true),从不给出输出。

解决方法很简单:去掉程序末尾的 while 循环。你不应该有那个;人们通常认为控制台程序在完成后会退出。我猜你已经猜到了,因为 Visual Studio 会在程序完成时自动关闭控制台窗口,但显然它不会使用 Ctrl+F5 来做到这一点,它你用的,所以我不确定。

【讨论】:

  • '\n' 不会导致刷新吗?它不会无限缓冲。
  • @JarraMcIntyre 这将刷新操作系统缓冲区(我认为;我更熟悉这样的 POSIX 低级细节),但 iostreams 有自己的内部缓冲区。我刚刚确认(再次,不是在 Windows 上)std::cout &lt;&lt; "Hello, world!\n"; 紧随其后的是无限循环或std::abort(); 不会在关闭sync_with_stdio 的情况下打印任何内容(不过,如果我注释掉该行,它会打印出来,这让我感到惊讶) .
  • 糟糕,我对某些缓冲发生在哪里感到困惑,这就是为什么我对sync_with_stdio 的效果感到惊讶的原因。如果您正在同步,那么您肯定会被行缓冲(因为底层 C 流是)并且 \n 会导致刷新。如果你关闭sync_with_stdio,那么我认为iostreams 根本没有行缓冲的概念。
  • 根据 cpp 参考 cout 确实提供了一些关于何时刷新的保证(std::flush,std::endl,在 std::system 调用之前),但是否 '\n' 刷新是实现定义的.我相信您的测试表明,如果启用了 sync_with_stdio,它确实会刷新 MS stl 实现。这是有道理的,因为 IIRC,stdout 确实在“\n”上刷新。如果您禁用该同步,则 std::cout 可以使用其自己的缓冲实现,该实现不一定具有相同的行为。
猜你喜欢
  • 2023-04-05
  • 1970-01-01
  • 2016-09-05
  • 1970-01-01
  • 2012-10-18
  • 1970-01-01
  • 2015-03-20
  • 2020-09-18
  • 1970-01-01
相关资源
最近更新 更多