为什么我的Python NumPy代码比C ++快?

发布于 2021-01-29 16:03:19

为什么这是Python NumPy代码,

import numpy as np
import time

k_max = 40000
N = 10000

data = np.zeros((2,N))
coefs = np.zeros((k_max,2),dtype=float)

t1 = time.time()
for k in xrange(1,k_max+1):
    cos_k = np.cos(k*data[0,:])
    sin_k = np.sin(k*data[0,:])
    coefs[k-1,0] = (data[1,-1]-data[1,0]) + np.sum(data[1,:-1]*(cos_k[:-1] - cos_k[1:]))
    coefs[k-1,1] = np.sum(data[1,:-1]*(sin_k[:-1] - sin_k[1:]))
t2 = time.time()

print('Time:')
print(t2-t1)

比以下C ++代码更快?

#include <cstdio>
#include <iostream>
#include <cmath>
#include <time.h>

using namespace std;

// consts
const unsigned int k_max = 40000;
const unsigned int N = 10000;

int main()
{
    time_t start, stop;
    double diff;
    // table with data
    double data1[ N ];
    double data2[ N ];
    // table of results
    double coefs1[ k_max ];
    double coefs2[ k_max ];
    // main loop
    time( & start );
    for( unsigned int j = 1; j<N; j++ )
    {
        for( unsigned int i = 0; i<k_max; i++ )
        {
            coefs1[ i ] += data2[ j-1 ]*(cos((i+1)*data1[ j-1 ]) - cos((i+1)*data1[ j ]));
            coefs2[ i ] += data2[ j-1 ]*(sin((i+1)*data1[ j-1 ]) - sin((i+1)*data1[ j ]));
        }
    }
    // end of main loop
    time( & stop );
    // speed result
    diff = difftime( stop, start );
    cout << "Time: " << diff << " seconds";
    return 0;
}

第一个显示:“时间:8秒”,第二个显示:“时间:11秒”

我知道NumPy是用C编写的,但我仍然认为C 示例会更快。我想念什么吗?有没有办法改善C 代码(或Python代码)?

代码的版本2

我已按照其中一项注释中的建议更改了C 代码(从动态表到静态表)。现在,C 代码更快,但仍然比Python版本慢得多。

代码的第3版

我从调试模式更改为发布模式,并将’k’从4000增加到40000。现在NumPy稍微快一点(从8秒到11秒)。

关注者
0
被浏览
143
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    我发现这个问题很有趣,因为每次遇到类似NumPy速度的主题(与C / C
    ++相比)时,总会有类似“它是一个薄包装纸,它的核心是用C编写的,所以很胖”的答案,但这没有解释为什么C应该比带有附加层(甚至是薄层)的C慢。

    答案是: 正确编译后,您的C ++代码不会比Python代码慢

    我已经做了一些基准测试,起初似乎NumPy出奇地快。但是我忘记了使用GCC优化编译。

    我再次计算了所有内容,还将结果与纯C版本的代码进行了比较。我正在使用GCC版本4.9.2和Python
    2.7.9(从具有相同GCC的源代码编译)。编译我用过的C 代码g++ -O3 main.cpp -o main,编译我用过的C代码gcc -O3 main.c -lm -o main。在所有示例中,我都会data用一些数字(0.1、0.4)填充变量,因为它会改变结果。我也将
    np.arrays 更改为使用doubles(dtype=np.float64),因为C
    示例中存在double。我的代码的纯C版本(类似):

    #include <math.h>
    #include <stdio.h>
    #include <time.h>
    
    const int k_max = 100000;
    const int N = 10000;
    
    int main(void)
    {
        clock_t t_start, t_end;
        double data1[N], data2[N], coefs1[k_max], coefs2[k_max], seconds;
        int z;
        for( z = 0; z < N; z++ )
        {
            data1[z] = 0.1;
            data2[z] = 0.4;
        }
    
        int i, j;
        t_start = clock();
        for( i = 0; i < k_max; i++ )
        {
            for( j = 0; j < N-1; j++ )
            {
                coefs1[i] += data2[j] * (cos((i+1) * data1[j]) - cos((i+1) * data1[j+1]));
                coefs2[i] += data2[j] * (sin((i+1) * data1[j]) - sin((i+1) * data1[j+1]));
            }
        }
        t_end = clock();
    
        seconds = (double)(t_end - t_start) / CLOCKS_PER_SEC;
        printf("Time: %f s\n", seconds);
        return coefs1[0];
    }
    

    对于k_max = 100000, N = 10000以下结果:

    • Python 70.284362秒
    • C ++ 69.133199秒
    • C 61.638186 s

    Python和C 基本上具有相同的时间,但请注意,存在一个长度为k_max的Python循环,与C / C 相比,它应该慢得多。是的。

    因为k_max = 1000000, N = 1000我们有:

    • Python 115.42766秒
    • C ++ 70.781380秒

    对于k_max = 1000000, N = 100

    • Python 52.86826秒
    • C ++ 7.050597秒

    因此,差异随分数增加k_max/N,但是python甚至N比python快得多k_max,例如,速度也不快k_max = 100, N = 100000

    • Python 0.651587秒
    • C ++ 0.568518秒

    显然,C / C
    ++和Python之间的主要速度差异在于for循环。但是我想找出在NumPy和C中对数组进行简单操作之间的区别。在代码中使用NumPy的优点包括:1.将整个数组乘以一个数字,2.计算整个数组的sin
    / cos, 3.对数组的所有元素求和,而不是分别对每个单个项目执行这些操作。因此,我准备了两个脚本来仅比较这些操作。

    Python脚本:

    import numpy as np
    from time import time
    
    N = 10000
    x_len = 100000
    
    def main():
        x = np.ones(x_len, dtype=np.float64) * 1.2345
    
        start = time()
        for i in xrange(N):
            y1 = np.cos(x, dtype=np.float64)
        end = time()
        print('cos: {} s'.format(end-start))
    
        start = time()
        for i in xrange(N):
            y2 = x * 7.9463
        end = time()
        print('multi: {} s'.format(end-start))
    
        start = time()
        for i in xrange(N):
            res = np.sum(x, dtype=np.float64)
        end = time()
        print('sum: {} s'.format(end-start))
    
        return y1, y2, res
    
    if __name__ == '__main__':
        main()
    
    # results
    # cos: 22.7199969292 s
    # multi: 0.841291189194 s
    # sum: 1.15971088409 s
    

    C脚本:

    #include <math.h>
    #include <stdio.h>
    #include <time.h>
    
    const int N = 10000;
    const int x_len = 100000;
    
    int main()
    {
        clock_t t_start, t_end;
        double x[x_len], y1[x_len], y2[x_len], res, time;
        int i, j;
        for( i = 0; i < x_len; i++ )
        {
            x[i] = 1.2345;
        }
    
        t_start = clock();
        for( j = 0; j < N; j++ )
        {
            for( i = 0; i < x_len; i++ )
            {
                y1[i] = cos(x[i]);
            }
        }
        t_end = clock();
        time = (double)(t_end - t_start) / CLOCKS_PER_SEC;
        printf("cos: %f s\n", time);
    
        t_start = clock();
        for( j = 0; j < N; j++ )
        {
            for( i = 0; i < x_len; i++ )
            {
                y2[i] = x[i] * 7.9463;
            }
        }
        t_end = clock();
        time = (double)(t_end - t_start) / CLOCKS_PER_SEC;
        printf("multi: %f s\n", time);
    
        t_start = clock();
        for( j = 0; j < N; j++ )
        {
            res = 0.0;
            for( i = 0; i < x_len; i++ )
            {
                res += x[i];
            }
        }
        t_end = clock();
        time = (double)(t_end - t_start) / CLOCKS_PER_SEC;
        printf("sum: %f s\n", time);
    
        return y1[0], y2[0], res;
    }
    
    // results
    // cos: 20.910590 s
    // multi: 0.633281 s
    // sum: 1.153001 s
    

    Python结果:

    • cos:22.7199969292 s
    • 多:0.841291189194 s
    • 总和:1.15971088409 s

    C结果:

    • cos:20.910590 s
    • 多:0.633281 s
    • 总和:1.153001 s

    如您所见,NumPy的速度非常快,但始终比纯C慢一些。



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看