为什么我的 python 函数比 c++ 中的函数运行得更快?

-4 c++ python

我一直在编写一个简单的测试来比较 c++ 相对于 python 的速度改进。我的结果出乎意料,c++ 几乎是用 python 编写的程序的三倍。我猜想 python 函数内部的循环中有一些使用迭代器或其他东西的东西。

C++代码

#include <ctime>
#include <chrono>
using namespace std;
using namespace chrono;

void mult(int* a, int b)
{
    for (size_t i = 0; i < 100000000; i++)
    {
        a[i] *= b;
    }
}

int main()
{
    srand(time(0));
    int* a = new int[100000000];
    int l = 100000000;
    for (int i = 0; i < l; ++i)
    {
        a[i] = rand();
    }
    auto start = high_resolution_clock::now();
    mult(a, 5);
    auto stop = high_resolution_clock::now();
    auto duration = duration_cast<milliseconds>(stop - start);
    cout << duration.count() << endl;
    delete[] a;
}
Run Code Online (Sandbox Code Playgroud)

Python代码

import time

def mult(x, a):
    for i in [x]:
        i *= a

x = np.random.random(100000000)
start = time.time() 
mult(x, 5)
elapsed = time.time()
elapsed = elapsed - start
print ("Time spent in (mult) is: ", elapsed)
Run Code Online (Sandbox Code Playgroud)

结果

C++:200毫秒

Python:65 毫秒

Kar*_*tel 6

此性能测试没有给出有用结果的原因有很多。

  1. 不要比较或关注release时间安排。使用 C 或 C++ 等语言的全部目的是启用(静态)编译器优化。所以实际上,结果是一样的。另一方面,重要的是要确保积极的编译器优化不会优化整个测试(由于未使用计算结果,或者由于程序中任何地方的未定义行为,或者由于编译器假设部分代码实际上无法到达,因为如果到达的话将会出现未定义的行为)。

  2. for i in [x]:是一个毫无意义的循环:它创建一个包含一个元素的 Python 列表,并迭代一次。一次迭代会执行此操作i *= a,即,它会相乘i,这就是 Numpy 数组。该代码只有在意外情况下才会起作用;碰巧 Numpy 数组专门定义了*一个循环并将每个元素相乘。这让我们...

  3. 使用 Numpy 的全部意义在于,它通过在幕后使用C 编写的代码来实现算法和数据结构来优化数字运算。i只是包含一个指向内存分配的指针,该内存分配看起来与 C 程序使用的内存分配基本相同,并且i *= a执行一些 O(1) 检查,然后设置并执行一个看起来与 C 代码中的循环基本相同的循环。

  4. 一般来说,这不是可靠的计时方法。那完全是另一锅鱼。Python 标准库包含一个timeit旨在使计时更容易并帮助避免一些更基本的陷阱的模块。但总的来说,正确地做到这一点是一个超出 Stack Overflow 问题范围的研究主题。


“但我想看到原生 Python 的缓慢性能,而不是 Numpy 的优化的东西 - ”

如果您只想查看 Python iteration的缓慢性能,那么您需要循环实际迭代数组的元素(并将它们写回):

def mult(x, a):
    for i in range(len(x)):
        x[i] *= a
Run Code Online (Sandbox Code Playgroud)

只是经验丰富的 Python 爱好者不会那样编写代码,因为range(len(这样很丑陋。Pythonic 方法是创建一个新列表:

def mult(x, a):
    return [i*a for i in x]
Run Code Online (Sandbox Code Playgroud)

这也将向您展示原生 Python数据结构的低效率(我们需要创建一个新列表,其中包含指向对象的指针int)。

在我的机器上,以这种方式处理 Numpy 数组实际上比原生 Python 列表还要慢。这可能是因为必须完成额外的工作才能将 Numpy 代码与本机 Python 连接起来,并将原始整数数据“装箱”到int对象中。