我写了以下程序来比较python和c/fortran的速度。 为了得到程序所使用的时间,我使用了 "time "命令。所有的 程序都计算了x的平方根 x+y y+z*z 其中x,y,z是浮点数。 我使用平方根,因为它是我参与的科学计算中最耗时的部分之一。 科学计算中最耗时的部分之一,而我也参与其中。

I got the following times:

fortran  0m29.9s //
c        0m20.7s //
python  30m10.8s

根据我做的简单测试,我发现Python不被推荐用于 科学计算。但可能我的代码效率很低。

你认为我可以仅仅为了这个简单的测试案例而使我的代码更有效率吗?

Fortran。

program root_square
implicit none
integer i,j
real x,y,z,r
x=1.0
y=2.0
z=3.0
do j=1,3000
    do i=1,1000000
        r=sqrt(x*x+y*y+z*z)
    enddo
enddo
end program root_square
#include "stdio.h"
#include "math.h"
int main (void)
float x=1.0,y=2.0,z=3.0,r;
int i,j;
for(j=0; j<3000; j++){
        for(i=0; i<1000000; i++) {
                r=sqrt(x*x+y*y+z*z);
return 0;

Python:

#!/usr/bin/env python
from math import sqrt
x = 1.0
y = 2.0
z = 3.0
for j in range(1,3001):
  for i in range(1,1000001):
    r = sqrt(x*x+y*y+z*z)
    
4 个评论
首先,在C例子中zyz是未初始化的。
你的Python代码创建了两个数字列表,一个有3000个数字,一个有100,000个数字。为什么你在Python中这样做,而在C或FORTRAN中却不这样做?另外,在Python中你使用双精度浮点,而在C和FORTRAN中你只使用单精度。为什么?
实际上,为了进行有意义的比较,你可能还想:(i) 在优化功能开启的情况下进行编译(例如,像-O3 -march=native的gcc,-fast的intel),以及(ii) 修改循环,使计算不能被移到循环之外(例如。例如,像r = r + sqrt((i+j)*x*x + y*y + z*z)这样的东西,最后再加一个print *,r)--因为编译器的优化会帮你做到这一点。正如有人所说,如果你需要双精度(对于python来说是这样的),你也应该在Fortran和C中分别使用real*8double
很好的例子,那个C语言的语法看起来很可疑。而且这只是一个非常简单的程序。
python
c
performance
fortran
armando
armando
发布于 2012-02-25
8 个回答
Haymo Kutschbach
Haymo Kutschbach
发布于 2012-02-25
已采纳
0 人赞同

我最近做了一个类似的测试用一个更现实的现实世界的算法。它涉及numpy、Matlab、FORTRAN和C#(通过ILNumerics).在没有具体优化的情况下,numpy似乎产生的代码效率比其他的低得多。当然--和以往一样--这只能说明一个普遍的趋势。你可以写出FORTRAN代码,最后运行速度比相应的numpy实现慢。但在大多数情况下,numpy会慢得多。这里是我测试的(平均)结果。

为了给你的例子中这种简单的浮点运算计时,所有的一切都归结于编译器生成 "最佳 "机器指令的能力。这里,涉及多少个编译步骤并不重要。.NET和numpy利用了不止一个步骤,首先编译成字节代码,然后在虚拟机中执行。但是优化结果的选项同样存在--在理论上。在实践中,现代FORTRAN和C编译器在优化执行速度方面做得更好。numpy(或更好的CPython,它主要用于numpy)在这一点上似乎表现得更糟。如果你想确保哪个框架最适合你的任务,你可以连接到一个调试器,调查可执行文件的最终机器指令。

然而,请记住,在一个更现实的情况下,浮点性能只在大型优化链的最末端才重要。这种差异往往被一个更强大的影响所掩盖:内存带宽。一旦你开始处理数组(这在大多数科学应用中很常见),你就必须考虑到内存管理的成本。框架在支持算法作者编写内存高效算法方面存在差异。在我看来,numpy比FORTRAN或C语言更难编写内存效率高的算法,但在这些语言中都不容易。(ILNumerics极大地改善了这一点。)

另一个重要的点是并行化。该框架是否支持你并行地执行你的计算?它的效率如何?还是我的个人观点:无论是C语言、FORTRAN语言还是numpy,都不容易使你的算法并行化。但是FORTRAN和C至少给了你这样做的机会,即使它有时需要使用特殊的编译器。其他框架(ILNumerics、Matlab)可以自动并行化。

如果你对非常小但昂贵的算法需要 "峰值性能",你最好使用FORTRAN或C语言,因为它们最终会产生更好的机器代码(在单处理器系统上)。然而,用C语言或FORTRAN语言编写较大的算法采取内存效率考虑到并行性往往会变得很麻烦。在这里,高级语言(如numpy、ILNumerics或Matlab)超过了低级语言。如果做得好的话--执行速度的差别往往可以忽略不计。不幸的是,numpy的情况往往不是这样的。

很好的概述,但OP说的是平方根函数,所以,虽然很有用,但这对于答案来说似乎有点太笼统了?(特别是当你的测试只是一个单一的算法时)。
@steabert 对。我是想说清楚,sqrt()函数不能单独存在。在现实世界中,为了决定一种语言,必须有更多的考虑。
Michael Dillon
Michael Dillon
发布于 2012-02-25
0 人赞同

有缺陷的基准。

如果你想对浮点运算进行计时,那么你应该首先对不做任何事情的循环进行计时(或者尽可能地接近不做任何事情)。为了避免优化整个循环,确保它所做的事情是将一个单字节的字符从一个数组移动到另一个数组。

然后用浮点计算再次计时,并减去第一次计时,得到一个更准确的数字。

另外,Python只有双倍的浮点数,所以一个更均匀的测试会确保其他语言也使用浮点数。而且正如其他人所提到的,Python被广泛用于科学计算,但那些科学家一般使用numpy库来进行矩阵计算,而不是写Python循环。

+但我看来,OP关注的不仅仅是FP的性能,而是语言的总体可行性。因此,相应的编译器对循环的翻译和优化方式也很重要。
那么 OP 不应该在 Python 中使用低效的 for 循环,而应该使用列表理解和生成器。事实是,科学家们使用Python,不是为了性能,而是为了灵活性。在需要高性能的地方,他们将 C 或 FORTRAN 子程序连接到 Python 应用程序中。
我同意。然而,他们总是希望减少必须跨越语言界限的情况。我从 "为什么我的.... 算法这么慢?"的问题数量中读到了这一点。
有没有可能告诉Python,我想执行的不是双精度而是浮点运算?
Scorpil
Scorpil
发布于 2012-02-25
0 人赞同

通常情况下,numpy在python中用于科学计算。你也许应该测试一下那个库。

eriktous
eriktous
发布于 2012-02-25
0 人赞同

请注意,r的计算并不依赖于循环变量,所以优化编译器可能会将计算移出循环,而只是将空循环运行所要求的次数;或者甚至完全删除该循环,只做平方根的计算。
一个真正聪明的优化器可能会注意到你没有对结果做任何事情,所以完整的程序可能会被优化掉而不改变输出(也就是什么都没有)。

Perry
Perry
发布于 2012-02-25
0 人赞同

你没有解释清楚你的测量目标是什么,所以很难回答你的测试代码是否能充分为你提供信息来满足这个目标。一般来说,基准的存在是为了告诉你一些非常具体的东西--你应该清楚地知道你通过进行基准测试想要弄清楚什么。你所尝试的上述类型的微观基准也因提供扭曲的答案而臭名昭著......

user1127914
发布于 2012-02-25
0 人赞同

也许你可以。 有一些Python的数学库可能可以更有效地完成你想要的任务。 由于Python范围的工作方式与C循环的工作方式完全不同,我将首先尝试解除这些循环。

steabert
steabert
发布于 2012-02-25
0 人赞同

在你开始这样比较时间之前,有一些事情你应该注意到。

  • As mentioned in another answer, it could be that the compiler optimizes the loop and the actual value away. Furthermore, even if you print the result, it could just pre-compute the square root.
  • You are using real in Fortran and float in C, so (depending on your system of course) the compiler will probably use the sqrtf library call in fortran, while in C you use sqrt instead of sqrtf, which you should use for a float.
  • In Python, you should use the numpy and scipy packages, they provide arrays on which you can do efficient whole-array operations, avoiding the looping in Python.
  • Boaz Tirosh
    Boaz Tirosh
    发布于 2012-02-25
    0 人赞同

    对于计算,我可能会尝试Haskell或ml...

    try this code in ML: