numpy.dot比本机C++11慢100倍
numpy.dot 100 times slower than native C++11
我有Matlab背景,一年前我买了一台笔记本电脑,我仔细选择了一台计算能力很强的笔记本电脑,这台机器有4个线程,在2.4GHz下为我提供了8个线程。这台机器证明了自己非常强大,使用简单的parfor循环,我可以利用所有处理器线程,用它我可以在许多问题和实验中获得接近8的加速。
这个美好的星期天,我在试验numpy,人们经常告诉我,numpy的核心业务是使用libblas高效实现的,甚至可能使用OpenMP等多个核心和库(使用OpenMP,你可以使用c风格的pragma创建类似parfor的循环)。
这是许多数值和机器学习算法的通用方法,你可以使用昂贵的高级运算(如矩阵乘法)来表达它们,但为了方便起见,你可以用昂贵的高级语言(如Matlab和python)来表达。此外,c(++)允许我们绕过GIL。
所以最酷的部分是,无论何时使用numpy,线性代数的东西都应该在python中处理得非常快。你只是有一些函数调用的开销,但如果它背后的计算量很大,那就可以忽略不计了。
因此,我甚至没有触及不是所有东西都可以用线性代数或其他numpy运算来表达的话题,而是对其进行了旋转:
t = time.time(); numpy.dot(range(100000000), range(100000000)); print(time.time() - t)
40.37656021118164
所以,在这40秒里,我看到我的机器上的8个线程中有一个100%工作,其他线程接近0%。我不喜欢这样,但即使有一个线程在工作,我也希望它能在大约0.几秒内运行。点积做100M+和*,所以我们有2400M/100M=每秒24个时钟周期,用于一个+、一个*和任何开销。
然而,对于+、*和开销,算法需要40*24=大约=1000个刻度(!!!!)。让我们在C++中这样做:
#include<iostream>
int main() {
unsigned long long result = 0;
for(unsigned long long i=0; i < 100000000; i++)
result += i * i;
std::cout << result << 'n';
}
闪电战:
herbert@machine:~$ g++ -std=c++11 dot100M.cc
herbert@machine:~$ time ./a.out
662921401752298880
real 0m0.254s
user 0m0.254s
sys 0m0.000s
0.254秒,几乎比numpy.dot.快100倍
我想,也许python3范围生成器是速度较慢的部分,所以我首先将所有100M数字存储在std::vector中(使用迭代push_back),然后再对其进行迭代,从而阻碍了我的c++11实现。这要慢得多,只需要不到4秒的时间,但速度仍然快了10倍。
我在ubuntu上使用"pip3-install-numpy"安装了我的numpy,它开始编译了一段时间,同时使用gcc和gfortran,此外,我看到有人提到blas头文件通过编译器输出。
为什么numpy.dot如此缓慢?
所以你的比较是不公平的。在python示例中,首先生成两个range对象,将它们转换为numpy数组,然后进行标量乘积。计算花费最少的部分。这是我电脑的号码:
>>> t=time.time();x=numpy.arange(100000000);numpy.dot(x,x);print time.time()-t
1.28280997276
并且没有生成阵列:
>>> t=time.time();numpy.dot(x,x);print time.time()-t
0.124325990677
为了完成,C版本需要大致相同的时间:
real 0m0.108s
user 0m0.100s
sys 0m0.007s
range
根据给定的参数生成一个列表,其中C中的for
循环只增加一个数字。
我同意花这么多时间生成一个列表在计算上似乎相当昂贵——再说一遍,这是一个大列表,而你正在请求其中的两个;-)
EDIT:如注释中所述,range
生成列表,而不是数组。
尝试用递增的while
循环或类似的方法替换range
方法,看看是否得到了更可容忍的结果。
- MSVC是否支持C++11样式的属性而不是__declspec
- 创建LinkedList退出,返回代码为-11(SIGSEGV)
- 我可以将一个用clang c++11编译的对象与另一个用c++17编译的对象链接起来吗
- 继承:构造函数,初始化C++11中基类的类C数组成员
- C++问题:用户认为数字1-100,程序提出问题不超过6次即可得到答案。无法正确
- 我想知道长双倍和双倍之间的区别
- 如何将模板转换为C++11之前的模板
- <T> 通过模板化运算符重载将 std::complex 乘以双倍
- c++11评估顺序(未定义的行为)
- C++中的VLA,扩展名为std=C++11
- 代码在我的计算机上运行良好,但是在将其提交给coursera时遇到未知的信号11问题
- "类模板示例<int>;"语句对 C++11 是什么意思?
- 如何编写一个使用n倍三元条件语句的C++布尔函数
- OpenMP 比串行代码慢 100 倍
- 填充整数列表比填充整数向量快 100 倍
- 使用C /CLI将图片插入Excel中,并获得100倍警告C4691
- C++11 getline 要求输入的两倍
- 为什么 Matlab 比 C++ 快 11 倍
- 这个用于写入任何数组内容的宏是否100%安全?c++11
- numpy.dot比本机C++11慢100倍