Python比C++快?这是怎么发生的

Python faster than C++? How does this happen?

本文关键字:C++ Python      更新时间:2023-10-16

我使用Windows7,对python3.22使用CPython,对C++使用MinGW的g++.exe(这意味着我使用libstdc++作为运行库)。我写了两个简单的程序来比较它们的速度。

Python:

x=0
while x!=1000000:
    x+=1
    print(x)

C++:

#include <iostream>
int main()
{
    int x = 0;
    while ( x != 1000000 )
    {
        x++;
        std::cout << x << std::endl;
    }
    return 0;
}

两者都未优化。

我先运行c++,然后通过交互式命令行运行python,这比直接启动.py文件慢得多。

然而,python的速度超过了c++,而且是它的两倍多。Python耗时53秒,c++耗时1分54秒。

是因为python对解释器进行了一些特殊的优化,还是因为C++必须引用和std,这会减慢它的速度并占用ram
还是其他原因?

编辑:我再次尝试,使用n而不是std::endl,并使用-O3标志进行编译,这次需要1分钟才能达到500000。

我的一位同事告诉我Python代码比C++代码快,然后以这个主题为例来证明他的观点。从其他答案中可以明显看出,问题中发布的C++代码出了什么问题。我仍然想总结一下我所做的基准测试,向他展示一个好的C++代码是如何快速的!

原始C++代码有两个问题:

  • 它使用std::endl在每次迭代中打印一条换行符。这是一个非常糟糕的主意,因为std::endl做的事情比简单地打印一行换行符还要多;它还迫使流刷新迄今为止累积的缓冲区;冲洗是一项成本高昂的操作,因为它必须处理硬件–输出设备。因此,第一个解决方案是:如果您想打印新行,只需使用'n'

  • 第二个问题不太明显,因为它在代码中看不到。它是在C++流的设计中。默认情况下,C++流在每次输入和输出操作后都会同步到C流,这样您的应用程序就可以毫无问题地混合std::coutstd::printf,以及std::cinstd::scanf。这个功能(是的,它是功能)在这种情况下是不需要的,所以我们可以禁用它,因为它有一点运行时开销(这不是问题;它不会让C++变得糟糕;它只是功能价格)。所以第二个修复是这样的:std::cout::sync_with_stdio(false);

这是最终优化的代码:

#include <iostream>
int main()
{
    std::ios_base::sync_with_stdio(false); 
    int x = 0;
    while ( x != 1000000 )
    {
         ++x;
         std::cout << x << 'n';
    }
}

并使用-O3标志编译它,并运行(和度量)为:

$ g++ benchmark.cpp -O3    #compilation
$ time ./a.out             #run
//..
real   0m32.175s
user   0m0.088s
sys    0m0.396s

并运行和测量python代码(发布在问题中):

$ time ./benchmark.py
//...
real  0m35.714s
user  0m3.048s
sys   0m4.456s

usersys时间告诉我们哪一个快,并且按什么顺序

希望这能帮助你消除疑虑。:-)

这里没有任何明显的内容。由于Python是用C编写的,所以它必须使用类似printf的东西来实现print。C++I/O流,如cout,通常以比printf慢得多的方式实现。如果你想把C++放在一个更好的基础上,你可以尝试更改为:

#include <cstdio>
int main()
{
    int x=0;
    while(x!=1000000)
    {
        ++x;
        std::printf("%dn", x);
    }
    return 0;
}

我确实改为使用++x而不是x++。几年前,人们认为这是一个有价值的"优化"。如果这种改变对程序的性能产生任何影响,我会心脏病发作(OTOH,我确信使用std::printf将对运行时性能产生巨大影响)。相反,我之所以进行更改,只是因为在增加x的值之前,您没有注意到它的值是多少,所以我认为在代码中这样说很有用。

我认为我们需要更多信息,但我希望您正在构建一个未优化的C++构建。尝试使用-O3标志构建它。(更了解GCC的人会有更多更好的建议)。然而,以下是一些来自完全不可信来源的时间安排:http://ideone.com.我每次运行5次,以获得时间上的一些方差度量,但只有原始C++发生了变化,而且变化不大。

Python:http://ideone.com/WBWB9时间:0.07-0.07s
您的C++:http://ideone.com/tzwQJ时间:0.05-0.06s
修改后的C++:http://ideone.com/pXJo3时间:0.001-0.00s

至于为什么我的C++比你的快,std::endl强制C++立即刷新缓冲区。'n'在没有强制缓冲区刷新的情况下执行换行,这要快得多。

(注意:我只运行到12773,因为ideone.com在进程显示一定数量的输出后会杀死进程,这是服务器给我的最多的输出)

std::endl滞后(它不仅仅是写一行换行符)。

直接使用'\n'将使C++代码运行得更快。

与中提出的问题相同为什么C++中从stdin读取行的速度比Python慢得多?但方向相反。

添加

std::cout.sync_with_stdio(false);

到程序的顶部