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

bus*_*uan 8 c++ python

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

蟒蛇:

x=0
while x!=1000000:
    x+=1
    print(x)
Run Code Online (Sandbox Code Playgroud)

C++:

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

两者都没有优化.

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

但是,python outran c ++的速度是原来的两倍多.Python花了53秒,c ++花了1分54秒.

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

编辑:我再次尝试,\n而不是std::endl,并用-O3旗帜编译,这次花了​​1分钟达到500,000.

Naw*_*waz 32

我的一位同事告诉我,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';
    }
}
Run Code Online (Sandbox Code Playgroud)

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

$ g++ benchmark.cpp -O3    #compilation
$ time ./a.out             #run

//..

real   0m32.175s
user   0m0.088s
sys    0m0.396s
Run Code Online (Sandbox Code Playgroud)

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

$ time ./benchmark.py

//...

real  0m35.714s
user  0m3.048s
sys   0m4.456s
Run Code Online (Sandbox Code Playgroud)

usersys时间告诉我们哪一个是快,通过什么样的顺序.

希望能帮助您消除疑虑.:-)


Max*_*ert 15

这里没有任何明显的东西.由于Python是用C语言编写的,因此它必须使用类似的东西printf来实现print.像C++ I/O Streams cout通常以比它慢得多的方式实现printf.如果你想让C++处于更好的基础,你可以尝试改为:

#include <cstdio>
int main()
{
    int x=0;
    while(x!=1000000)
    {
        ++x;
        std::printf("%d\n", x);
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

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

  • @bosukxuan:如果不输出任何内容,C++编译器可能会删除整个循环......这并不能证明`cout`确实是问题所在. (9认同)
  • 哦,上帝,感谢你的帮助....我删除了打印和cout,python花了10多秒钟才计算到10 ^ 8,而C++在闪光灯中完成(不是比喻或夸张,我的意思是几分之一,是的,一个真正的闪光).所以问题就在于cout ......现在我学到了很多教训.非常感谢! (5认同)
  • 所以你说c ++只比python慢​​,因为python使用最直接的方式来实现print,而这种差异是由print事件造成的?嗯......我想我应该去试试没有印刷品. (2认同)
  • @busukxuan:写入控制台总是很慢.您是否尝试将每个程序的输出重定向到文件?你的小程序几乎肯定是I/O绑定的,写入文件将消除缓慢的控制台写入. (2认同)

Moo*_*uck 11

我认为我们需要更多信息,但我希望您构建一个未经优化的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.00 S-0.00S

至于为什么我的C++比你的更快,std::endl 强迫 C++立即刷新缓冲区. '\n'没有强制缓冲区刷新的换行,这快得多.

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

  • @busukxuan:错了.如果你有一个没有输出的循环,那么C++将完全_nothing.它没有计算_anything_.这就是基准测试很难的原因. (4认同)

qua*_*tum 6

std :: endl滞后,使用'\n'会使c ++更快.


gjp*_*jpc 5

与为什么在 C++ 中从 stdin 读取行比 Python 慢得多?但方向相反。

添加

std::cout.sync_with_stdio(false);

到程序顶部