C++ - 与 Numpy 中的矢量版本相比,Argsort 效率低的矢量版本实现
C++ - vector version implement of argsort low effiency compared to the one in numpy
这是我做的比较。np.argsort
定时于 float32 ndarray 由 1,000,000 个元素组成。
In [1]: import numpy as np
In [2]: a = np.random.randn(1000000)
In [3]: a = a.astype(np.float32)
In [4]: %timeit np.argsort(a)
86.1 ms ± 1.59 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
这是一个C++程序执行相同的过程,但在引用此答案的向量上。
#include <iostream>
#include <vector>
#include <cstddef>
#include <algorithm>
#include <opencv2/opencv.hpp>
#include <numeric>
#include <utility>
int main()
{
std::vector<float> numbers;
for (int i = 0; i != 1000000; ++i) {
numbers.push_back((float)rand() / (RAND_MAX));
}
double e1 = (double)cv::getTickCount();
std::vector<size_t> idx(numbers.size());
std::iota(idx.begin(), idx.end(), 0);
std::sort(idx.begin(), idx.end(), [&numbers](const size_t &a, const size_t &b)
{ return numbers[a] < numbers[b];});
double e2 = (double)cv::getTickCount();
std::cout << "Finished in " << 1000 * (e2 - e1) / cv::getTickFrequency() << " milliseconds." << std::endl;
return 0;
}
它打印Finished in 525.908 milliseconds.
,并且比numpy版本慢得多。那么谁能解释一下是什么让np.argsort
这么快?谢谢。
Edit1:np.__version__
返回在Python 3.6.6 |Anaconda custom (64-bit)
上运行的1.15.0
,g++ --version
打印8.2.0。操作系统是Manjaro Linux。
g++
中使用-O2
和-O3
标志进行编译,并在 216.515 毫秒和 205.017 毫秒内得到结果。这是一个改进,但仍然比numpy版本慢。(参考这个问题(Edit3:另一种方法是用 C 替换向量,例如数组:float numbers[1000000];
。之后,运行时间约为 100 毫秒(+/-5 毫秒(。完整代码在这里:
#include <iostream>
#include <vector>
#include <cstddef>
#include <algorithm>
#include <opencv2/opencv.hpp>
#include <numeric>
#include <utility>
int main()
{
//std::vector<float> numbers;
float numbers[1000000];
for (int i = 0; i != 1000000; ++i) {
numbers[i] = ((float)rand() / (RAND_MAX));
}
double e1 = (double)cv::getTickCount();
std::vector<size_t> idx(1000000);
std::iota(idx.begin(), idx.end(), 0);
std::sort(idx.begin(), idx.end(), [&numbers](const size_t &a, const size_t &b)
{ return numbers[a] < numbers[b];});
double e2 = (double)cv::getTickCount();
std::cout << "Finished in " << 1000 * (e2 - e1) / cv::getTickFrequency() << " milliseconds." << std::endl;
return 0;
}
我采用了您的实现并用10000000
项对其进行了测量。大约花了1.7秒。
现在我介绍了一个类
class valuePair {
public:
valuePair(int idx, float value) : idx(idx), value(value){};
int idx;
float value;
};
与初始化为
std::vector<valuePair> pairs;
for (int i = 0; i != 10000000; ++i) {
pairs.push_back(valuePair(i, (double)rand() / (RAND_MAX)));
}
和排序比完成
std::sort(pairs.begin(), pairs.end(), [&](const valuePair &a, const valuePair &b) { return a.value < b.value; });
此代码将运行时间缩短到 1.1 秒。我认为这是由于更好的缓存一致性,但距离 python 结果还很远。
想法:
-
不同的底层算法:。
np.argsort
默认使用快速排序,C++
中的实现可能取决于您的编译器。 -
函数调用开销:我不确定根据这篇文章,情况并非如此C++
编译器是否内联了您的比较函数。否则,调用此函数也可能会引入一些开销。 -
编译器标志 ?
相关文章:
- 为cl.exe(Visual Studio代码)指定命令行C++版本
- 导入库可以跨dll版本工作吗
- 在调用FreeLibrary后,释放动态链接到具有相同版本的CRT堆的DLL的内存
- 在clang++预处理器中确定gcc工具链版本
- 码头化的C++应用程序是否向后兼容早期的内核版本
- 不同的Visual Studio版本中缺少.dll
- 用符号版本替换对函数的所有调用
- luaL_dofile在已知良好的字节码上失败,可以使用未编译的版本
- 正在解码MSVC 32位版本的程序集(作业).没有手术做什么
- 我需要分发哪些版本的可再分发文件
- CV_OCL_RUN宏如何在OpenCV(版本3.4.5)的goodFeaturesToTrack实现中工作?
- 在运行时读取 libstdc++ 版本
- 如何声明一个可以在整个程序中使用的全局 2d 3d 4d .. 数组(堆版本)变量?
- FindPackageHandleStandardArgs.cmake:137 的 CMake 错误(消息):找不到 Boost (缺少:正则表达式)(找到合适的版本"1.72.0",
- Vulkan SDK 版本 1.1.85.0 在 Kubuntu 18.10 上链接
- 如何正确实现与基类不同的版本?
- 从预处理器获取 Windows 版本(C++ Win32)
- 表达式 SFINAE:如何根据类型是否包含具有一个或多个参数的函数来选择模板版本
- 如何在C++中将 Python 字符串转换为其转义版本?
- C++ - 与 Numpy 中的矢量版本相比,Argsort 效率低的矢量版本实现