为什么这个C++代码比C#变体慢

why this C++ code is slower compared to C# variant

本文关键字:代码 C++ 为什么      更新时间:2023-10-16

最近,我们有一个需求,其中有超过100000个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() << " secsn";
}

似乎有很多文件所做的工作太少,所以这里的主要瓶颈是磁盘IO。如果每个文件都有一些复杂且消耗CPU的任务,那么C++版本可以更快,但对于小任务,这是无关紧要的,因为IO是问题

尽管有些人认为,只要你不使用某些缓慢的功能(如反射),c#就一点也不慢——事实上,人们最终会更快地编码,并且有更少的模糊错误,所以有更多的时间来优化性能和逻辑,而不是修复错误,这意味着它最终会更快。。。

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

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