Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/124.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 提高字符串的分配性能_C++_Linux_Memory Management_Boost_Memory Pool - Fatal编程技术网

C++ 提高字符串的分配性能

C++ 提高字符串的分配性能,c++,linux,memory-management,boost,memory-pool,C++,Linux,Memory Management,Boost,Memory Pool,我将java GC测试程序移植到C++(参见下面的代码)以及Python。java和python的性能远远大于C++,我认为这是因为每次调用新< /COD>每次都要创建字符串。我曾尝试使用Boost的快速池分配器,但这实际上使性能从700ms恶化到1200ms。我使用分配器是错误的,还是我应该做些别的事情 编辑:使用g++-O3-march=native--std=c++11 garbage.cpp-lboost\u系统编译。g++是4.8.1版 Python的一次迭代大约需要300毫秒,Jav

我将java GC测试程序移植到C++(参见下面的代码)以及Python。java和python的性能远远大于C++,我认为这是因为每次调用<代码>新< /COD>每次都要创建字符串。我曾尝试使用Boost的
快速池分配器
,但这实际上使性能从700ms恶化到1200ms。我使用分配器是错误的,还是我应该做些别的事情

编辑:使用
g++-O3-march=native--std=c++11 garbage.cpp-lboost\u系统编译。g++是4.8.1版
Python的一次迭代大约需要300毫秒,Java的一次迭代大约需要50毫秒
std::allocator
给出大约700ms,而boost::fast\u pool\u allocator
给出大约1200ms

#include <string>
#include <vector>
#include <chrono>
#include <list>
#include <iostream>
#include <boost/pool/pool_alloc.hpp>
#include <memory>
//#include <gc/gc_allocator.h>


using namespace std;
#include <sstream>
typedef boost::fast_pool_allocator<char> c_allocator;
//typedef std::allocator<char> c_allocator;
typedef basic_string<char, char_traits<char>, c_allocator> pool_string;
namespace patch {
    template <typename T> pool_string to_string(const T& in) {
        std::basic_stringstream<char, char_traits<char>, c_allocator> stm;
        stm << in;
        return stm.str();
    }
}


#include "mytime.hpp"

class Garbage {
public:
    vector<pool_string> outer;
    vector<pool_string> old;
    const int nThreads = 1;
    //static auto time = chrono::high_resolution_clock();

    void go() {
//        outer.resize(1000000);
        //old.reserve(1000000);
        auto tt = mytime::msecs();
        for (int i = 0; i < 10; ++i) {
            if (i % 100 == 0) {
                cout << "DOING AN OLD" << endl;
                doOld();
                tt = mytime::msecs();
            }

            for (int j = 0; j < 1000000/nThreads; ++j)
                outer.push_back(patch::to_string(j));

            outer.clear();
            auto t = mytime::msecs();
            cout << (t - tt) << endl;
            tt = t;
        }
    }

    void doOld() {
        old.clear();
        for (int i = 0; i < 1000000/nThreads; ++i)
            old.push_back(patch::to_string(i));
    }
};

int main() {
    Garbage().go();
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
//#包括
使用名称空间std;
#包括
typedef boost::fast_pool_分配器c_分配器;
//类型定义std::分配器c_分配器;
typedef基本字符串池字符串;
命名空间修补程序{
模板池字符串到字符串(常量T&in){
std::basic_stringstream stm;

stm问题在于每次都使用一个新的字符串流来转换整数

修复它:

namespace patch {
    template <typename T> pool_string to_string(const T& in) {
        return boost::lexical_cast<pool_string>(in);
    }
}
查看它

完整代码供参考:

#include <boost/pool/pool_alloc.hpp>
#include <chrono>
#include <iostream>
#include <list>
#include <memory>
#include <sstream>
#include <string>
#include <vector>
#include <boost/lexical_cast.hpp>
//#include <gc/gc_allocator.h>

using string = std::string;

namespace patch {
    template <typename T> string to_string(const T& in) {
        return boost::lexical_cast<string>(in);
    }
}

class Timer
{
    typedef std::chrono::high_resolution_clock clock;
    clock::time_point _start;
  public:
    Timer() { reset(); }
    void reset() { _start = now(); }
    double elapsed()
    {
        using namespace std::chrono;
        auto e = now() - _start;
        return duration_cast<nanoseconds>(e).count()*1.0e-9;
    }
    clock::time_point now()
    {
        return clock::now();
    }
};


class Garbage {
    public:
        std::vector<string> outer;
        std::vector<string> old;
        const int nThreads = 1;

        void go() {
            outer.resize(1000000);
            //old.reserve(1000000);
            Timer timer;

            for (int i = 0; i < 10; ++i) {
                if (i % 100 == 0) {
                    std::cout << "DOING AN OLD" << std::endl;
                    doOld();
                }

                for (int j = 0; j < 1000000/nThreads; ++j)
                    outer.push_back(patch::to_string(j));

                outer.clear();
                std::cout << timer.elapsed() << std::endl;
                timer.reset();
            }
        }

        void doOld() {
            old.clear();
            for (int i = 0; i < 1000000/nThreads; ++i)
                old.push_back(patch::to_string(i));
        }
};

int main() {
    Garbage().go();
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
//#包括
使用string=std::string;
命名空间修补程序{
模板字符串到_字符串(常量T&in){
返回boost::词法转换(in);
}
}
班级计时器
{
typedef std::chrono::高分辨率时钟;
时钟:时间点开始;
公众:
计时器(){reset();}
void reset(){u start=now();}
双时间()
{
使用名称空间std::chrono;
自动e=现在()-\u开始;
返回持续时间_cast(e).count()*1.0e-9;
}
时钟:现在的时间点()
{
返回时钟::现在();
}
};
类垃圾{
公众:
std::向量外部;
std::向量old;
常数int=1;
void go(){
外部。调整大小(1000000);
//旧储备(1000000);
定时器;
对于(int i=0;i<10;++i){
如果(i%100==0){

std::cout因为我的机器上没有使用boost,所以我将代码简化为使用标准C++11
来处理字符串(从而意外地“修复”了sehe发现的问题),并得到以下结果:

#include <string>
#include <vector>
#include <chrono>
#include <list>
#include <iostream>
#include <memory>
//#include <gc/gc_allocator.h>
#include <sstream>
using namespace std;


class Timer
{
    typedef std::chrono::high_resolution_clock clock;
    clock::time_point _start;
    public:
    Timer() { reset(); }
    void reset() { _start = now(); }
    double elapsed()
    {
        using namespace std::chrono;
        auto e = now() - _start;
        return duration_cast<nanoseconds>(e).count()*1.0e-9;
    }
    clock::time_point now()
    {
        return clock::now();
    }
};


class Garbage {
public:
    vector<string> outer;
    vector<string> old;
    const int nThreads = 1;
Timer timer;

    void go() {
//        outer.resize(1000000);
        //old.reserve(1000000);
        for (int i = 0; i < 10; ++i) {
            if (i % 100 == 0) {
                cout << "DOING AN OLD" << endl;
                doOld();
            }

            for (int j = 0; j < 1000000/nThreads; ++j)
                outer.push_back(to_string(j));

            outer.clear();
            cout << timer.elapsed() << endl;
            timer.reset();
        }
    }

    void doOld() {
        old.clear();
        for (int i = 0; i < 1000000/nThreads; ++i)
            old.push_back(to_string(i));
    }
};

int main() {
    Garbage().go();
}
2014年4月18日星期五发布的Clang3.5BuildwithSource在相同的编译器选项下给出了类似的结果


我的处理器是AMD Phenom(tm)II X4 965,运行频率为3.6GHz(如果我没记错的话)。

这似乎表明你确实用错了:
池分配器
用于连续块(例如
新字符[n]
),快速池分配器
用于单个事物(例如
新字符
).谢谢。我刚试过这个,但等它打印一个号码我就烦了(也就是说,花了很长时间)@user315118-在您的帖子中没有提到使用的编译器、在构建应用程序时使用的编译器选项以及优化等。如果您要发布声称在某个时间单位内执行的代码,则必须同时发布您的编译器和使用的选项。否则,我们正确地假设您使用的是旧版本编译器、损坏的编译器或未完全启用优化的编译。你是说每个循环需要0.7-1.2秒吗?在我的机器上,我使用标准分配器大约需要0.19秒。要么你在相当慢的硬件上运行,要么你没有启用优化。@PaulMcKenzie谢谢。我用这个信息更新了这个问题像往常一样,这是“不是你认为它花时间的地方”的问题……这是一个好地方。@Matstpeterson确实如此。像往常一样,这是“profile,profile,profile”(虽然我在这一个中没有使用):)@sehe太好了!我没有考虑stringstream的分配。将其静态删除会得到类似的结果。虽然在我的计算机上,迭代的最佳性能仍然只有175ms左右。我用你的计时器替换了我的计时器,现在大约为100ms。所以对mats Peterson加倍强调。@mats Peterson绝对…我被你的计时器宠坏了我的GCed语言哈哈。我实际上做了一个调用图,但令人钦佩地看了一眼它列出的所有模板功能并关闭了它:/这就像说前轮驱动汽车比后轮驱动汽车快。真正影响速度的不是哪个车轮驱动汽车,而是整体设计、发动机功率,如果转弯是正确的涉及轮胎、悬架等-前轮或后轮驱动在整个方案中是相当小的因素。我相信这个类比与“垃圾收集与非垃圾收集”相比相当好。在我正在进行的编译器项目中,我只是懒散地忽略所有释放的内存,而依赖于在退出时清理整个内容。显然不会永远工作,但是…感谢STL的回答。当我实际编写/调试我正在使用的代码时,
cygwin
,它有一个中断的
to_string
实现,因此是一个使用stringstreams。是的,不使用windows有它的优点…;)
#include <string>
#include <vector>
#include <chrono>
#include <list>
#include <iostream>
#include <memory>
//#include <gc/gc_allocator.h>
#include <sstream>
using namespace std;


class Timer
{
    typedef std::chrono::high_resolution_clock clock;
    clock::time_point _start;
    public:
    Timer() { reset(); }
    void reset() { _start = now(); }
    double elapsed()
    {
        using namespace std::chrono;
        auto e = now() - _start;
        return duration_cast<nanoseconds>(e).count()*1.0e-9;
    }
    clock::time_point now()
    {
        return clock::now();
    }
};


class Garbage {
public:
    vector<string> outer;
    vector<string> old;
    const int nThreads = 1;
Timer timer;

    void go() {
//        outer.resize(1000000);
        //old.reserve(1000000);
        for (int i = 0; i < 10; ++i) {
            if (i % 100 == 0) {
                cout << "DOING AN OLD" << endl;
                doOld();
            }

            for (int j = 0; j < 1000000/nThreads; ++j)
                outer.push_back(to_string(j));

            outer.clear();
            cout << timer.elapsed() << endl;
            timer.reset();
        }
    }

    void doOld() {
        old.clear();
        for (int i = 0; i < 1000000/nThreads; ++i)
            old.push_back(to_string(i));
    }
};

int main() {
    Garbage().go();
}
$ g++ -O3 -std=c++11 gc.cpp
$ ./a.out
DOING AN OLD
0.414637
0.189082
0.189143
0.186336
0.184449
0.18504
0.186302
0.186055
0.183123
0.186835