【发布时间】:2018-08-23 09:20:07
【问题描述】:
这是我做的比较。 np.argsort 在一个包含 1,000,000 个元素的 float32 ndarray 上进行计时。
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++ 程序执行相同的过程,但在引用 this answer 的向量上。
#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__ 返回 1.15.0,它在 Python 3.6.6 |Anaconda custom (64-bit) 和 g++ --version 上运行,打印 8.2.0。操作系统是 Manjaro Linux。
Edit2:我尝试在 这被删除了,因为我错误地在拔下笔记本电脑的直流适配器的情况下运行测试,这会导致它变慢。在公平的竞争中,C 数组和向量版本的性能相同(大约需要 100 毫秒)。g++ 中使用-O2 和-O3 标志进行编译,并在216.515 毫秒和205.017 毫秒内得到结果。这是一个改进,但仍然比 numpy 版本慢。 (Referring to this question)
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;
}
【问题讨论】:
-
你不应该只是在
c++版本中为sort计时吗? -
@EdChum 但是vector idx 应该被看作是排序结果的容器,所以我认为它的初始化进程应该加入计时
-
平台、编译器、numpy 版本(以及它的构建选项)?您是否进行了优化编译?在本地尝试这个,我得到 122ms 的 Numpy,115ms 的 c++....(当然是发布版本,调试要慢一个数量级)
-
现在我使用 clang++ 和 libc++ 获得了几乎相同的运行时间(~107-110 ms)。 g++ 大约慢了 10%。
-
我发现自己在时间上犯了一个非常幼稚的错误。如果拔掉 DC 适配器,我的笔记本电脑可能会为了省电而变慢。很抱歉之前和现在在公平的环境中提供误导性信息,向量和 C-array 的性能与@ead 所说的一样。
标签: python c++ performance numpy