Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.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++ 为什么排序向量<;wstring>;使用自定义wcscmp和wmemcmp比较器比默认值快得多?_C++_String_Performance_Sorting_Stl - Fatal编程技术网

C++ 为什么排序向量<;wstring>;使用自定义wcscmp和wmemcmp比较器比默认值快得多?

C++ 为什么排序向量<;wstring>;使用自定义wcscmp和wmemcmp比较器比默认值快得多?,c++,string,performance,sorting,stl,C++,String,Performance,Sorting,Stl,似乎使用基于自定义wcscmp和基于wmemcmp的比较器对vector进行排序要比默认行为快得多(大约1000毫秒) 64位版本(VS2015): 可编译代码: /////////////////////////////////////////////////////////////////////////////// // // Compare sorting a vector<wstring> with: // - default comparator // - custo

似乎使用基于自定义
wcscmp
和基于
wmemcmp
的比较器对
vector
进行排序要比默认行为快得多(大约1000毫秒)

64位版本(VS2015):

可编译代码:

///////////////////////////////////////////////////////////////////////////////
//
// Compare sorting a vector<wstring> with:
//  - default comparator
//  - custom wcscmp()-based comparator
//  - custom wmemcmp()-based comparator
// 
///////////////////////////////////////////////////////////////////////////////

#include <string.h>     // wcscmp, wmemcmp

#include <algorithm>    // std::shuffle, std::sort
#include <iostream>     // std::cout
#include <random>       // std::mt19937
#include <string>       // std::wstring
#include <vector>       // std::vector

#include <Windows.h>    // Windows Platform SDK

using namespace std;


//=============================================================================
//                        Performance Counter Helpers
//=============================================================================

long long Counter()
{
    LARGE_INTEGER li;
    ::QueryPerformanceCounter(&li);
    return li.QuadPart;
}

long long Frequency()
{
    LARGE_INTEGER li;
    ::QueryPerformanceFrequency(&li);
    return li.QuadPart;
}

void PrintTime(const long long start, const long long finish, const char * const s)
{
    cout << s << ": " << (finish - start) * 1000.0 / Frequency() << " ms \n";
}


//=============================================================================
//                           Performance Tests
//=============================================================================

bool CompareUsingWcscmp(const std::wstring& a, const std::wstring& b) noexcept
{
    // a < b
    return wcscmp(a.c_str(), b.c_str()) < 0;
}

bool CompareUsingWmemcmp(const std::wstring& a, const std::wstring& b) noexcept
{
    const size_t count = min(a.size(), b.size());
    return wmemcmp(a.data(), b.data(), count) < 0;
}

int main()
{
    // Build a vector of strings generated starting from "Lorem Ipsum"
    const auto shuffled = []() -> vector<wstring>
    {
        const wstring lorem[] =
        {
            L"Lorem ipsum dolor sit amet, consectetuer adipiscing elit.",
            L"Maecenas porttitor congue massa. Fusce posuere, magna sed",
            L"pulvinar ultricies, purus lectus malesuada libero,",
            L"sit amet commodo magna eros quis urna.",
            L"Nunc viverra imperdiet enim. Fusce est. Vivamus a tellus.",
            L"Pellentesque habitant morbi tristique senectus et netus et",
            L"malesuada fames ac turpis egestas. Proin pharetra nonummy pede.",
            L"Mauris et orci. [*** add more chars to prevent SSO ***]"
        };

        vector<wstring> v;
#ifdef _DEBUG
        constexpr int kTestIterationCount = 1000;
#else
        constexpr int kTestIterationCount = 200'000;
#endif
        for (int i = 0; i < kTestIterationCount; ++i)
        {
            for (const auto & s : lorem)
            {
                v.push_back(s + L" (#" + to_wstring(i) + L")");
            }

        }

        mt19937 prng(1980);
        shuffle(v.begin(), v.end(), prng);
        return v;
    }();

    long long start = 0;
    long long finish = 0;

    vector<wstring>  v1 = shuffled;
    vector<wstring>  w1 = shuffled;
    vector<wstring>  z1 = shuffled;

    vector<wstring>  v2 = shuffled;
    vector<wstring>  w2 = shuffled;
    vector<wstring>  z2 = shuffled;

    vector<wstring>  v3 = shuffled;
    vector<wstring>  w3 = shuffled;
    vector<wstring>  z3 = shuffled;

    start = Counter();
    sort(v1.begin(), v1.end());
    finish = Counter();
    PrintTime(start, finish, "Default1");

    start = Counter();
    sort(w1.begin(), w1.end(), CompareUsingWcscmp);
    finish = Counter();
    PrintTime(start, finish, "wcscmp1 ");

    start = Counter();
    sort(z1.begin(), z1.end(), CompareUsingWmemcmp);
    finish = Counter();
    PrintTime(start, finish, "wmemcmp1");

    cout << '\n';

    start = Counter();
    sort(v2.begin(), v2.end());
    finish = Counter();
    PrintTime(start, finish, "Default2");

    start = Counter();
    sort(w2.begin(), w2.end(), CompareUsingWcscmp);
    finish = Counter();
    PrintTime(start, finish, "wcscmp2 ");

    start = Counter();
    sort(z2.begin(), z2.end(), CompareUsingWmemcmp);
    finish = Counter();
    PrintTime(start, finish, "wmemcmp2");

    cout << '\n';

    start = Counter();
    sort(v3.begin(), v3.end());
    finish = Counter();
    PrintTime(start, finish, "Default3");

    start = Counter();
    sort(w3.begin(), w3.end(), CompareUsingWcscmp);
    finish = Counter();
    PrintTime(start, finish, "wcscmp3 ");

    start = Counter();
    sort(z3.begin(), z3.end(), CompareUsingWmemcmp);
    finish = Counter();
    PrintTime(start, finish, "wmemcmp3");
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//
//将向量排序与以下内容进行比较:
//-默认比较器
//-自定义基于wcscmp()的比较器
//-自定义基于wmemcmp()的比较器
// 
///////////////////////////////////////////////////////////////////////////////
#包括//wcscmp、wmemcmp
#包括//std::shuffle、std::sort
#include//std::cout
#包括//标准::mt19937
#include//std::wstring
#include//std::vector
#包括//Windows平台SDK
使用名称空间std;
//=============================================================================
//性能计数器助手
//=============================================================================
长计数器()
{
大整数李;
::QueryPerformanceCounter(&li);
返回li.QuadPart;
}
长频率
{
大整数李;
::QueryPerformanceFrequency(&li);
返回li.QuadPart;
}
无效打印时间(const long long start、const long long finish、const char*const s)
{

cout这可能是您的库的
std::less
(这是
std::sort()
)的默认比较器)的一个弱点。为了进行比较,我制作了一个可移植版本的测试:

#include <cstring>

#include <algorithm>
#include <chrono>
#include <functional>
#include <iostream>
#include <random>
#include <string>
#include <vector>

// override this by compiling with (e.g.)
//   g++ -DITERATION_COUNT=1000
#ifndef ITERATION_COUNT
#define ITERATION_COUNT 200000
#endif

template<typename T>
struct time_printer
{
    T func;

    friend std::ostream& operator<<(std::ostream& os, const time_printer& p)
    {
        using Duration = std::chrono::duration<double, std::chrono::milliseconds::period>;
        auto begin = std::chrono::steady_clock::now();
        p.func();
        auto end = std::chrono::steady_clock::now();
        Duration time_taken = end - begin;
        return os << time_taken.count();
    }
};

template<typename T>
time_printer<T> print_time(T fun) { return {fun}; }


int main()
{
    // Build a vector of strings generated starting from "Lorem Ipsum"
    const auto shuffled = []() {
        static const std::wstring lorem[] = {
            L"Lorem ipsum dolor sit amet, consectetuer adipiscing elit.",
            L"Maecenas porttitor congue massa. Fusce posuere, magna sed",
            L"pulvinar ultricies, purus lectus malesuada libero,",
            L"sit amet commodo magna eros quis urna.",
            L"Nunc viverra imperdiet enim. Fusce est. Vivamus a tellus.",
            L"Pellentesque habitant morbi tristique senectus et netus et",
            L"malesuada fames ac turpis egestas. Proin pharetra nonummy pede.",
            L"Mauris et orci. [*** add more chars to prevent SSO ***]"
        };

        std::vector<std::wstring> v;
        auto const kTestIterationCount = ITERATION_COUNT;
        v.reserve(std::size(lorem) * kTestIterationCount);
        for (int i = 0;  i < kTestIterationCount;  ++i) {
            auto const suffix = L" (#" + std::to_wstring(i) + L")";
            for (auto const& s: lorem) {
                v.push_back(s + suffix);
            }
        }

        std::shuffle(v.begin(), v.end(), std::mt19937{1980});
        return v;
    }();

    // name, function
    using comparator = std::pair<const char *, std::function<bool(const std::wstring&,const std::wstring&)>>;
    static const comparator comparators[] = {
        {" default", [](const auto& a, const auto& b){return a < b;} },
        {"std_less", std::less<std::wstring>{} },
        {"  wcscmp", [](const auto& a, const auto& b){return std::wcscmp(a.c_str(), b.c_str()) < 0;} },
        {" wmemcmp", [](const auto& a, const auto& b){return std::wmemcmp(a.data(), b.data(), std::min(a.size(), b.size())) < 0;;} }
    };

    static const auto passes = 3u;
    static const auto ncomp = std::size(comparators);

    std::vector<std::vector<std::wstring>> inputs(ncomp * passes, shuffled);

    for (auto i = 0u;  i < inputs.size();  ++i) {
        auto pass = i % ncomp;
        auto round = i / ncomp + 1;
        std::cout << comparators[pass].first << " round " << round << ": "
                  << print_time([&]{std::sort(inputs[i].begin(), inputs[i].end(), comparators[pass].second);})
                  << std::endl;
    }

    // make sure they all sorted correctly
    return std::count_if(inputs.begin(), inputs.end(),
                         [](auto const& v){ return !std::is_sorted(v.begin(), v.end());});
}

您是否可以重试并比较
wstring
何时由
new
分配?codekaizer提出了一个很好的观点。可能是获取wstring的缓冲区更方便缓存我有VS2017,那里的
wcscmp
版本要慢230-240毫秒。@codekaizer:不考虑
wstring
本身是如何分配的,其内容将在堆上(请参阅关于长字符串的注释,这样您就不会得到小字符串优化)。traits compare的机器代码看起来经过了精心优化。我试图使您的谓词同样低效,同时挖掘size()并使用wmemcmp()。令人惊讶的是,它的速度快了很多。很难看出,这是vtune的工作。谢谢。我用VS2015编译了您的代码,得到的数字比我的原始代码(相同的硬件)慢。无论如何,默认行为仍然比自定义的
wmemcmp
/
wcscmp
(例如,
默认值3535.07、wcscmp 2728.27、wmemcmp 2805.93
)。
#include <cstring>

#include <algorithm>
#include <chrono>
#include <functional>
#include <iostream>
#include <random>
#include <string>
#include <vector>

// override this by compiling with (e.g.)
//   g++ -DITERATION_COUNT=1000
#ifndef ITERATION_COUNT
#define ITERATION_COUNT 200000
#endif

template<typename T>
struct time_printer
{
    T func;

    friend std::ostream& operator<<(std::ostream& os, const time_printer& p)
    {
        using Duration = std::chrono::duration<double, std::chrono::milliseconds::period>;
        auto begin = std::chrono::steady_clock::now();
        p.func();
        auto end = std::chrono::steady_clock::now();
        Duration time_taken = end - begin;
        return os << time_taken.count();
    }
};

template<typename T>
time_printer<T> print_time(T fun) { return {fun}; }


int main()
{
    // Build a vector of strings generated starting from "Lorem Ipsum"
    const auto shuffled = []() {
        static const std::wstring lorem[] = {
            L"Lorem ipsum dolor sit amet, consectetuer adipiscing elit.",
            L"Maecenas porttitor congue massa. Fusce posuere, magna sed",
            L"pulvinar ultricies, purus lectus malesuada libero,",
            L"sit amet commodo magna eros quis urna.",
            L"Nunc viverra imperdiet enim. Fusce est. Vivamus a tellus.",
            L"Pellentesque habitant morbi tristique senectus et netus et",
            L"malesuada fames ac turpis egestas. Proin pharetra nonummy pede.",
            L"Mauris et orci. [*** add more chars to prevent SSO ***]"
        };

        std::vector<std::wstring> v;
        auto const kTestIterationCount = ITERATION_COUNT;
        v.reserve(std::size(lorem) * kTestIterationCount);
        for (int i = 0;  i < kTestIterationCount;  ++i) {
            auto const suffix = L" (#" + std::to_wstring(i) + L")";
            for (auto const& s: lorem) {
                v.push_back(s + suffix);
            }
        }

        std::shuffle(v.begin(), v.end(), std::mt19937{1980});
        return v;
    }();

    // name, function
    using comparator = std::pair<const char *, std::function<bool(const std::wstring&,const std::wstring&)>>;
    static const comparator comparators[] = {
        {" default", [](const auto& a, const auto& b){return a < b;} },
        {"std_less", std::less<std::wstring>{} },
        {"  wcscmp", [](const auto& a, const auto& b){return std::wcscmp(a.c_str(), b.c_str()) < 0;} },
        {" wmemcmp", [](const auto& a, const auto& b){return std::wmemcmp(a.data(), b.data(), std::min(a.size(), b.size())) < 0;;} }
    };

    static const auto passes = 3u;
    static const auto ncomp = std::size(comparators);

    std::vector<std::vector<std::wstring>> inputs(ncomp * passes, shuffled);

    for (auto i = 0u;  i < inputs.size();  ++i) {
        auto pass = i % ncomp;
        auto round = i / ncomp + 1;
        std::cout << comparators[pass].first << " round " << round << ": "
                  << print_time([&]{std::sort(inputs[i].begin(), inputs[i].end(), comparators[pass].second);})
                  << std::endl;
    }

    // make sure they all sorted correctly
    return std::count_if(inputs.begin(), inputs.end(),
                         [](auto const& v){ return !std::is_sorted(v.begin(), v.end());});
}