Cha*_*han 70 c++ sorting performance stl
根据Scott Meyers的说法,在他的Effective STL书中 - 第46项.他声称这std::sort比std::qsort内联的事实要快670%.我测试了自己,我看到qsort更快:(!有谁可以帮我解释这个奇怪的行为?
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <cstdio>
const size_t LARGE_SIZE = 100000;
struct rnd {
int operator()() {
return rand() % LARGE_SIZE;
}
};
int comp( const void* a, const void* b ) {
return ( *( int* )a - *( int* )b );
}
int main() {
int ary[LARGE_SIZE];
int ary_copy[LARGE_SIZE];
// generate random data
std::generate( ary, ary + LARGE_SIZE, rnd() );
std::copy( ary, ary + LARGE_SIZE, ary_copy );
// get time
std::time_t start = std::clock();
// perform quick sort C using function pointer
std::qsort( ary, LARGE_SIZE, sizeof( int ), comp );
std::cout << "C quick-sort time elapsed: " << static_cast<double>( clock() - start ) / CLOCKS_PER_SEC << "\n";
// get time again
start = std::clock();
// perform quick sort C++ using function object
std::sort( ary_copy, ary_copy + LARGE_SIZE );
std::cout << "C++ quick-sort time elapsed: " << static_cast<double>( clock() - start ) / CLOCKS_PER_SEC << "\n";
}
Run Code Online (Sandbox Code Playgroud)
这是我的结果:
C quick-sort time elapsed: 0.061
C++ quick-sort time elapsed: 0.086
Press any key to continue . . .
Run Code Online (Sandbox Code Playgroud)
更新
有效的STL第3版(2001)
第7章使用STL编程
第46项:考虑函数对象而不是函数作为算法参数.
最好的祝福,
Pup*_*ppy 95
std :: clock()不是可行的时钟.您应该使用特定于平台的更高分辨率计时器,例如Windows高性能计时器.更重要的是,调用clock()的方式是首先将文本输出到控制台,该控制台包含在时间中.这肯定会使测试无效.此外,请确保使用所有优化进行编译.
最后,我复制并粘贴了你的代码,qsort为0.016,std :: sort为0.008.
ras*_*mus 18
我很惊讶没有人提到缓存.
在您的代码中,您首先触摸ary和*ary_copy*,以便它们在qsort时驻留在缓存中.在qsort期间,*ary_copy*可能会被驱逐.在std :: sort时,必须从内存或更大(读取更慢)的缓存级别获取元素.这当然取决于您的缓存大小.
尝试反转测试,即从运行std :: sort开始.
正如有些人指出的那样; 使阵列更大将使测试更公平.原因是大型数组不太可能适合缓存.
tem*_*def 12
未启用优化的两种排序算法应具有相当的性能.C++ sort倾向于明显优势的原因qsort是编译器可以内联进行比较,因为编译器具有关于用于执行比较的函数的类型信息.您是否在启用优化的情况下运行这些测试 如果没有,请尝试将其打开并再次运行此测试.
Zan*_*ynx 10
qsort可能比预期运行得更好的另一个原因是较新的编译器可以通过函数指针进行内联和优化.
如果C头定义了qsort的内联实现而不是在库中实现它并且编译器支持间接函数内联,那么qsort可以和std :: sort一样快.
在我的机器上添加一些肉类(将数组变成1000万个元素并在数据部分中移动它)并进行编译
g++ -Wall -O2 -osortspeed sortspeed.cpp
Run Code Online (Sandbox Code Playgroud)
我得到的结果
C quick-sort time elapsed: 3.48
C++ quick-sort time elapsed: 1.26
Run Code Online (Sandbox Code Playgroud)
还应注意可能配置为根据系统负载以可变速度运行的现代“绿色” CPU。进行基准测试时,这种行为会使您发疯(在我的计算机上,我有一个小的脚本,用于修复进行速度测试时使用的CPU时钟)。
编写准确的基准测试很困难,所以让Nonius为我们做吧!让我们在一个包含一百万个随机整数的向量上测试qsort,std::sort没有内联和std::sort内联(默认)。
// sort.cpp
#define NONIUS_RUNNER
#include <nonius.h++>
#include <random>
#include <algorithm>
// qsort
int comp(const void* a, const void* b) {
const int arg1 = *static_cast<const int*>(a);
const int arg2 = *static_cast<const int*>(b);
// we can't simply return a - b, because that might under/overflow
return (arg1 > arg2) - (arg1 < arg2);
}
// std::sort with no inlining
struct compare_noinline {
__attribute__((noinline)) bool operator()(const int a, const int b) {
return a < b;
}
};
// std::sort with inlining
struct compare {
// the compiler will automatically inline this
bool operator()(const int a, const int b) {
return a < b;
}
};
std::vector<int> gen_random_vector(const size_t size) {
std::random_device seed;
std::default_random_engine engine{seed()};
std::uniform_int_distribution<int> dist{std::numeric_limits<int>::min(), std::numeric_limits<int>::max()};
std::vector<int> vec;
for (size_t i = 0; i < size; i += 1) {
const int rand_int = dist(engine);
vec.push_back(rand_int);
}
return vec;
}
// generate a vector of a million random integers
constexpr size_t size = 1'000'000;
static const std::vector<int> rand_vec = gen_random_vector(size);
NONIUS_BENCHMARK("qsort", [](nonius::chronometer meter) {
// Nonius does multiple runs of the benchmark, and each one needs a new
// copy of the original vector, otherwise we'd just be sorting the same
// one over and over
const size_t runs = static_cast<size_t>(meter.runs());
std::vector<std::vector<int>> vectors{runs};
std::fill(vectors.begin(), vectors.end(), rand_vec);
meter.measure([&](const size_t run) {
std::vector<int>& current_vec = vectors[run];
std::qsort(current_vec.data(), current_vec.size(), sizeof(int), comp);
return current_vec;
});
});
NONIUS_BENCHMARK("std::sort noinline", [](nonius::chronometer meter) {
const size_t runs = static_cast<size_t>(meter.runs());
std::vector<std::vector<int>> vectors{runs};
std::fill(vectors.begin(), vectors.end(), rand_vec);
meter.measure([&](const size_t run) {
std::vector<int>& current_vec = vectors[run];
std::sort(current_vec.begin(), current_vec.end(), compare_noinline{});
return current_vec;
});
});
NONIUS_BENCHMARK("std::sort inline", [](nonius::chronometer meter) {
const size_t runs = static_cast<size_t>(meter.runs());
std::vector<std::vector<int>> vectors{runs};
std::fill(vectors.begin(), vectors.end(), rand_vec);
meter.measure([&](const size_t run) {
std::vector<int>& current_vec = vectors[run];
std::sort(current_vec.begin(), current_vec.end(), compare{});
return current_vec;
});
});
Run Code Online (Sandbox Code Playgroud)
使用 Apple Clang 7.3.0 编译,
$ clang++ -std=c++14 -stdlib=libc++ -O3 -march=native sort.cpp -o sort
$ ./sort
Run Code Online (Sandbox Code Playgroud)
并在我的 1.7 GHz i5 Macbook Air 上运行它,我们得到
qsort 211 ms +/- 6 ms
std::sort noinline 127 ms +/- 5 ms
std::sort inline 87 ms +/- 4 ms
Run Code Online (Sandbox Code Playgroud)
因此std::sort,没有内联的速度大约比qsort(可能是由于不同的排序算法)快 1.7 倍,而内联的颠簸速度大约快 2.4 倍。当然是令人印象深刻的加速,但远低于 670%。
| 归档时间: |
|
| 查看次数: |
56145 次 |
| 最近记录: |