与VB.net实现相比,为什么Python中的算法速度慢?

时间:2014-02-13 19:13:44

标签: python

以下代码在Python 3.3上运行大约需要两分钟,但是等效的VB.net版本在不到一秒的时间内运行。我在这里做的特别低效会让它在Python上变慢吗?或者它只是一个较慢的翻译? Python的数学库会慢得多吗? (将x,x1和x3初始化为浮点数没有太大区别。)

inc = 2*3*5*7
for x in range(inc,200000,inc):
    n = 0
    y = x * x + x

    for x1 in range(x+1, y):
        x2 = x1 / (x1 - x) * x
        x3 = round(x2)
        if abs(x2 - x3) < 0.0000001:
            if x3 < x1: break
            n += 1
    if n > 500: print(x, n)

(我意识到有更好的算法来完成同样的事情。我有兴趣改进这个的Python实现,以便学习更多的Python。)

VB代码:

Dim x, x1, x2, x3, y As Double
Dim n As Integer

For x = 0 To 200000 Step 2 * 3 * 5 * 7
  n = 0
  y = x * x + x
  For x1 = x + 1 To y
    x2 = x1 / (x1 - x) * x
    x3 = Round(x2)
    If Math.Abs(x2 - x3) < 0.0000001 Then
      If x3 < x1 Then Exit For
      n += 1
      End If
    Next x1
  If n > 500 Then sb.Append(x & " " & x1 & " " & x3 & " " & n & vbCrLf)
  Next x

4 个答案:

答案 0 :(得分:4)

你没有编写特别低效的代码,没有。您只是看到纯粹解释的语言(而不是特别快的语言)和编译语言之间的正常性能差异。作为证据,请考虑通过在cProfile下运行代码生成的配置文件十五秒:

% python3 -m cProfile stackoverflow.py & pid=$\!; sleep 15; kill -INT $!
55440 608
60060 608
65520 608
69300 563
73920 527
78540 608
         32855602 function calls in 14.969 seconds
   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1   10.557   10.557   14.969   14.969 so.py:1(<module>)
 16427796    0.646    0.000    0.646    0.000 {built-in method abs}
        1    0.000    0.000   14.969   14.969 {built-in method exec}
        6    0.000    0.000    0.000    0.000 {built-in method print}
 16427797    3.766    0.000    3.766    0.000 {built-in method round}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

您最大的成本中心似乎是round函数,但即使只占用运行时的三分之一。这表明问题不是您自己的代码的任何特定部分,而是低效算法和慢速解释器的组合。

答案 1 :(得分:1)

问题不在于python数学--- python数学运算与任何其他语言一样快。问题是python字节码执行速度慢,这很慢。

您可以使用以下技术加快速度:

  • 使用numpy数组并进行适当的矢量化(或数组programming)。请注意,你不仅需要使用numpy,还需要使用矢量化删除python循环。我一直在使用它,在大多数情况下,你可以加快计算速度20-100倍。
  • 使用cython或weave编写将直接翻译为C的代码。请参阅this文章。

如果你想学习python,我会说numpy是要走的路,就像cython和weave一样,你将学习如何更多地编写C代码。

答案 2 :(得分:1)

你可以随时使用cythonC - 如果你的python代码。 (抱歉奇怪的__future__xrange和百分号)我正在使用Python 2.7ipython notebook

from __future__ import division

%%timeit
inc = 2*3*5*7
for x in xrange(inc,200000,inc):
    n = 0
    y = x * x + x
    for x1 in xrange(x+1, y):
        x2 = x1 / (x1 - x) * x
        x3 = round(x2)
        if abs(x2 - x3) < 0.0000001:
            if x3 < x1: break
            n += 1
    if n > 500: a,b = x,n

1 loops, best of 3: 1min 5s per loop


%load_ext cythonmagic
%%cython -f
#cython: boundscheck=False
#cython: wraparound=False
from __future__ import division
from libc.math cimport fabs
from libc.math cimport round as cround
import time
cdef int inc = 2*3*5*7
cdef int x
cdef int n
cdef int y
cdef int x1
cdef double x2
cdef double x3
cdef int a, b
t0 = time.time()
for x in range(inc,200000,inc):
    n = 0
    y = x * x + x

    for x1 in range(x+1, y):
        x2 = x1 / (x1 - x) * x
        x3 = cround(x2)
        if fabs(x2 - x3) < 0.0000001:
            if x3 < x1: break
            n += 1
    if n > 500: a,b = x,n
t1 = time.time()
print "time elapsed:", t1 - t0, "sec"

time elapsed: 0.900931119919 sec

答案 3 :(得分:0)

一个快速修复是在pypy而不是python中运行它。因为pypy有一个JIT编译器,所以它会编译这些循环。

在我的机器上,pypy在36秒内完成,而python仍然没有回复。

编辑:我不确定算法是做什么的,但是如果你试图看看x2是否是一个整数,那么使用.is_integer将python3占用的时间减半,并将pypy降低到1秒。似乎在某些情况下它会返回错误的答案,但为了完整起见,我将包含代码。

inc = 2*3*5*7
for x in range(inc,200000,inc):
    n = 0
    y = x * x + x

    for x1 in range(x+1, y):
        x2 = float(x1) / (x1 - x) * x
        if x2.is_integer():
            if x2 < x1: break
            n += 1
    if n > 500: print(x, n)