代码之家  ›  专栏  ›  技术社区  ›  shrpq

编写性能C++定位器

  •  -5
  • shrpq  · 技术社区  · 7 年前

    在阅读了有效的现代C++之后,我试图找出最好的方法,在C++类中如何为参数集传递参数;想象下面的场景:

    您所编写的应用程序解析输入文件(如cvs格式),将其输入模型类,然后将实例列表传递给数据库驱动程序进行大容量插入。

    我们可以谈论最新的和最伟大的C++ 14,我用一列写了我的尝试:

    class Person {
        std::wstring _name;
    public:
        template<typename T>
        inline void setName(T&& name) { _name = std::forward<T>(name); }
    };
    

    我还编写了以下代码片段来测试性能:

    const auto start = std::chrono::system_clock::now();
    std::vector<std::shared_ptr<Person>> vec;
    for (auto i = 0; i < 999999; i++)
    {
        auto p = std::make_shared<Person>();
        p->setName(L"John Chester Doe");
    
        vec.emplace_back(p);
    }   
    
    const auto end = std::chrono::system_clock::now();
    std::cout << "Took " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << " ms" << std::endl;
    

    在我的系统上,这需要大约175ms的时间,使用msvc2017版本x64和/o2编译,关闭sdl,没有安全检查(/sdl-/gs-)。出于好奇,我在C里也试过同样的方法:

    class Person
    {
        public string Name { get; set; }
    } 
    
    
    var sw = System.Diagnostics.Stopwatch.StartNew();
    var i = 0;
    var vec = new System.Collections.Generic.List<Person>();
    for (; i < 999999; i++)
    {
        var p = new Person();
        p.Name = "John Chester Doe";
        vec.Add(p);
    }
    sw.Stop();
    System.Console.WriteLine("Took {0}ms", sw.ElapsedMilliseconds);
    

    在释放模式下产生77ms!所以我的问题自然是我做错了什么?为什么我的C++代码在本质上相同的操作上比C代码慢?

    我尝试使用C++中的Stutt(没有差异),通过const REF(慢)传递值,传递值为STD::移动(较慢)。我也尝试使用No.Excel(没有很大的差别):STD::字符串(没有大的差别)。

    谢谢!

    编辑

    感谢大家的建议,非常感谢。我想达到的最好方法是:

    std::vector<Person> vec;
    vec.reserve(999999);
    for (auto i = 0; i < 999999; i++)
    {
        vec.emplace_back();
        vec.back().setName(L"John Chester Doe");
    }
    

    2 回复  |  直到 7 年前
        1
  •  0
  •   Swift - Friday Pie    7 年前

    “把桔子比作苹果”是我在这里能给出的最好的描述。你的C代码最接近C++的等价物:

    #include <iostream>
    #include <deque>
    #include <chrono>
    #include <string>
    
    struct Person {
        std::wstring _name;
    
        Person() = default;
        Person(Person&& p) = default;
        Person(const Person& p) = default;
        Person(const std::wstring& n) : _name(n) {}
    };
    
    int main()
    {
        std::deque<Person> vec; 
        const std::wstring n =  L"John Chester Doe";
        const auto start = std::chrono::system_clock::now();
        for (auto i = 0; i < 999999; i++)
        {
            vec.emplace_back(n);
        }   
    
        const auto end = std::chrono::system_clock::now();
        std::cout << "Took " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << " ms" << std::endl;
    }
    

    比你的变体快至少3倍。也许我可以使它更快,将所有内存的分配移动到deque的初始化中,但这会将循环更改为远程循环。是的,C是和Java一样做的事情。它试图将大多数可预测的工作卸载到编译时间,例如收集相似的文本、投影可用内存和更有效地分配它等等。这主要是因为CLR工作原理类似于Java机器。

        2
  •  0
  •   shrpq    7 年前

    我的理解是C编译器在后台做什么,大致转换为下面的C++代码:

    class Person {
        std::wstring _name;
    public:
        template<typename T>
        inline void setName(T&& name) { _name = std::forward<T>(name); }
    };
    

    插入部分:

    std::vector<Person> vec;
    vec.reserve(999999);
    for (auto i = 0; i < vec.size(); i++)
    {
        vec.emplace_back();
        vec.back().setName(L"John Chester Doe");
    }
    

    再次感谢您的时间,如果有其他建议如何改进这一点,我很高兴听到。