为什么我的python/numpy示例比纯C实现更快?

Art*_*nin 7 c python performance numpy

我在python和C.中有几乎相同的代码.Python示例:

import numpy
nbr_values = 8192
n_iter = 100000

a = numpy.ones(nbr_values).astype(numpy.float32)
for i in range(n_iter):
    a = numpy.sin(a)
Run Code Online (Sandbox Code Playgroud)

C示例:

#include <stdio.h>
#include <math.h>
int main(void)
{
  int i, j;
  int nbr_values = 8192;
  int n_iter = 100000;
  double x;  
  for (j = 0; j < nbr_values; j++){
    x = 1;
    for (i=0; i<n_iter; i++)
    x = sin(x);
  }
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

当我运行两个例子时,会发生奇怪的事情:

$ time python numpy_test.py 
real    0m5.967s
user    0m5.932s
sys     0m0.012s

$ g++ sin.c
$ time ./a.out 
real    0m13.371s
user    0m13.301s
sys     0m0.008s
Run Code Online (Sandbox Code Playgroud)

看起来python/numpy比C快两倍.上面的实验有什么错误吗?你怎么解释它?

PS我有Ubuntu 12.04,8G内存,核心i5顺便说一句

Omn*_*ous 18

首先,打开优化.其次,细微之处很重要.你的C代码肯定不是"基本相同".

这是等效的C代码:

sinary2.c:

#include <math.h>
#include <stdlib.h>

float *sin_array(const float *input, size_t elements)
{
    int i = 0;
    float *output = malloc(sizeof(float) * elements);
    for (i = 0; i < elements; ++i) {
        output[i] = sin(input[i]);
    }
    return output;
}
Run Code Online (Sandbox Code Playgroud)

sinary.c:

#include <math.h>
#include <stdlib.h>

extern float *sin_array(const float *input, size_t elements)

int main(void)
{
    int i;
    int nbr_values = 8192;
    int n_iter = 100000;
    float *x = malloc(sizeof(float) * nbr_values);  
    for (i = 0; i < nbr_values; ++i) {
        x[i] = 1;
    }
    for (i=0; i<n_iter; i++) {
        float *newary = sin_array(x, nbr_values);
        free(x);
        x = newary;
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

结果:

$ time python foo.py 

real    0m5.986s
user    0m5.783s
sys 0m0.050s
$ gcc -O3 -ffast-math sinary.c sinary2.c -lm
$ time ./a.out 

real    0m5.204s
user    0m4.995s
sys 0m0.208s
Run Code Online (Sandbox Code Playgroud)

程序必须分成两部分的原因是为了哄骗优化器.否则它将意识到整个循环根本没有效果并优化它.将事物放在两个文件中并不能让编译器看到sin_array它编译时可能出现的副作用,main因此它必须假设它实际上有一些并反复调用它.

由于多种原因,您的原始程序根本不相同.一个是你在C版本中有嵌套循环而你没有在Python中.另一个是您正在使用Python版本中的值数组而不是C版本.另一个是您在Python版本中创建和丢弃数组,而不是在C版本中.最后,您使用float的是Python版本和doubleC版本.

简单地调用该sin函数适当的次数并不能进行等效测试.

此外,优化器对于C来说是一个非常大的优点.当你想知道速度比较时,将优化器尚未用于其他任何事情的C代码进行比较是不对的.当然,你还需要注意.C优化器非常复杂,如果你正在测试一些真正没有做任何事情的东西,C优化器可能会注意到这个事实而根本就没有做任何事情,导致程序的速度非常快.