【问题标题】:why this C++ code is slower compared to C# variant为什么这个 C++ 代码比 C# 变体慢
【发布时间】:2013-02-20 05:42:20
【问题描述】:

最近,我们有一个要求,其中有超过 100,000 个 xml 文件,并且所有这些文件都需要修改 xml 中的特定数据。简单的 perl 命令可以完成这项工作,但 perl 没有安装在文件所在的机器上。因此,我编写了一个小的 C# 代码来完成这项工作。

private static void ModifyXML(string[] args)
{
      Stopwatch sw = new Stopwatch();
      sw.Start();
      string path = @args[0];
      string opath = @args[1];
      string token = "value_date=\"20121130\"";
      string target = "value_date=\"20121019\"";

      Parallel.ForEach(Directory.EnumerateFiles(path), (file) =>
      {
           StringBuilder sb = new StringBuilder(File.ReadAllText(file));
           sb.Remove(0, 55);
           sb.Replace(token, target);
           var filename = file.Split(new char[] { '\\' }).Last();                
           File.WriteAllText(string.Format("{0}\\{1}", opath, filename), sb.ToString());
       });
       TimeSpan ts = sw.Elapsed;
       Console.WriteLine("Took {0} secs", ts.TotalSeconds);
}

我决定实现 C++ 版本。事实证明,C++ 版本并没有明显快于 C# 版本。在两个版本中运行了几次。事实上,在某些运行期间它与 C# 版本一样快。

对于 C#,我使用 .NET 4.0,对于 C++,它是 VC10。

void FileHandling(std::string src, std::string dest)
{
     namespace fs = boost::filesystem;
    auto start = boost::chrono::system_clock::now();
    string token = "value_date=\"20121130\"";
    string target = "value_date=\"20121019\"";
    fs::directory_iterator end_iter;
    fs::directory_iterator dir_itr(src);
    vector<fs::path> files;
    files.insert(files.end(), dir_itr, end_iter);
    string dest_path = dest + "\\";
    parallel_for_each(files.begin(), files.end(), [=](const fs::path& filepath)
    {
        ifstream inpfile (filepath.generic_string());
        string line;
        line.insert(line.end(), istreambuf_iterator<char>(inpfile), istreambuf_iterator<char>());
        line.erase(0, 55);
        auto index = line.find(token, 0);
        if (index != string::npos)
        {
            line.replace(index, token.size(), target);
        }
        ofstream outfile(dest_path + filepath.filename().generic_string());
        outfile << line;
    });

    boost::chrono::duration<double> finish = boost::chrono::system_clock::now() - start;
    std::cout << "Took " << finish.count() << " secs\n";
}

【问题讨论】:

  • 您为什么希望它们有所不同?
  • 你是如何编译 C++ 代码的?
  • @jogojapan ,发布版本。
  • C++ 不会让你的硬盘更快。
  • 顺便说一句,我还要注意,对于这种情况,您可能会发现串行处理比并行处理更快。硬盘一次只能提供一个数据流,并行处理多个文件可能会导致更多的磁盘查找。

标签: c# c++ ppl


【解决方案1】:

似乎您有很多文件,但完成的工作太少,所以这里的主要瓶颈是磁盘 IO。如果每个文件都有一些复杂且消耗 CPU 的任务,则可以更快地获得 C++ 版本,但在小型任务上则无关紧要,因为 IO 是问题

【讨论】:

    【解决方案2】:

    尽管有些人认为,只要您不使用反射等某些慢速功能,c# 一点也不慢 - 事实上,人们最终编码速度更快,并且隐藏的错误更少,因此有更多时间用于优化性能和逻辑,而不是修复错误,这意味着它最终会更快......

    除了您在 C# 代码中使用更常见的库之外,这些库通常由 MS 开发人员编写和优化 - 与必须在 c++ 代码中滚动您自己的函数相比..

    【讨论】:

    • C# 确实有一些 C++ 或其他本机编译的语言中不存在的开销,因为通常会发生诸如 JIT 之类的事情来将 IL 转换为本机代码,以及可以像拳击之类的让你慢下来。生产力论点在很大程度上是无关紧要的......人们在他们最了解的情况下编码最好,因此用 C# 编码的 C++ 程序员的生产力低于用 C++ 编码的 C++ 程序员。都是相对的。 C# 中的好代码可以击败 C++ 中的坏代码,反之亦然。
    • 这太笼统了,并不是这个问题的正确答案。生产力与所提出的问题无关,即为什么一段代码比另一段运行得更快。
    【解决方案3】:

    当您“编译”C# 代码时,“编译器”会生成中间语言代码 (MSIL),然后此代码在运行时由 dotnet 框架的 JIT 编译器编译为本机代码。 JIT 编译的代码针对您执行代码的环境进行了高度优化。每个函数只发生一次,一旦函数被编译为本机代码,它将被重用,直到应用程序终止。因此,如果您一遍又一遍地调用一个函数,JIT 生成和优化的代码可能会优于一般编译的 C++ 代码

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-11-04
      • 1970-01-01
      • 2021-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-29
      相关资源
      最近更新 更多