当前位置: 首页 > 面试题库 >

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

焦光霁
2023-03-14
问题内容

为什么这是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秒)。


问题答案:

我发现这个问题很有趣,因为每次遇到类似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慢一些。



 类似资料:
  • 我最近用Java写了一个计算密集型算法,然后把它翻译成C++。令我吃惊的是,C++的执行速度要慢得多。我现在已经编写了一个更短的Java测试程序,以及一个相应的C++程序-参见下面。我的原始代码具有大量的数组访问功能,测试代码也是如此。C++的执行时间要长5.5倍(请参阅每个程序末尾的注释)。 以下1st21条评论后的结论... null null Java代码: C++代码:

  • 答案可能存在于某个地方,但我找不到。我从我正在创建的一个算法中得出这个问题。实质上是,如果s1包含s2,则返回true,忽略希腊语/英语字符差异。例如,字符串“nai,of course”包含字符串“vaxi”。不过,这与我的问题无关。

  • 问题内容: 以下是C 中的一个简单循环。计时器正在使用QueryPerformanceCounter(),并且非常准确。我发现Java占用了C 60%的时间,这不是吗?我在这里做错了什么?即使是严格的别名(此处未包含在代码中)也完全没有帮助… 此C ++的运行时间约为9.5秒。我正在将Intel Compiler 12.1用于主机处理器优化(专门针对我的处理器),并将所有功能都最大化。所以这是最好

  • Java: 如果java以微弱优势击败了C和C#我不会感到惊讶,但速度快了20倍?! 文件的格式如下: 另外,我认为值得注意的是,java在NetBeans中运行时大约需要11秒(即使是在“运行”模式下,而不是在“调试”模式下)。 我也尝试编译为C++而不是C,但没有什么不同。 我对C和C#都使用VS2015。 Java: 好吧,我按照建议重新做了测试: 首先,我在C和C#中都使用了类/struc

  • 问题内容: 下面是分别用和编码的简单过程(对于那些对此过程感到好奇的人,这是针对Euler项目5号问题的解决方案)。 我的问题是,下面的代码仅需9秒即可迭代,而代码完成则需要283秒(确切地说,在Python 3.4.3-64位上为283秒,在Python 2.7.9-32位上为329秒)。 到目前为止,我已经编码的两种类似的过程和与执行时间的差异,具有可比性。但是,这次,经过的时间之间存在极大的

  • 为什么我的SIMD向量4长度函数比原始向量长度方法慢3倍? SIMD矢量4长度函数: 幼稚的实现: 我用GCC(Ubuntu7.4.0-1Ubuntu1~18.04.1)7.4.0: SSE版本输出: 纯C版本输出:

  • 这似乎与对象没有被实例化有关,尽管我不太明白为什么。有人知道出什么事了吗?

  • 包装呈现值;导入java。util。扫描仪; 公共类PresentValue{ }问题是写一个方法presentValue来执行此计算。该方法应接受未来值、年利率和年数作为参数。它应该返回现值,即您今天需要存入的金额。在一个程序中演示该方法,该程序允许用户试验公式项的不同值。 这里是公式P=F/(1r)^2