English 中文(简体)
为什么等效的沙里法越慢
原标题:Why is equivalent Python code so much slower

有些人可以解释,为什么以下三维法(实施Euclid的算法以找到最普遍的分法者)比鲁比的对应法低3倍左右?

内容:

from sys import argv,stderr

def gcd(m, n):
    if n > m:
        m, n = n, m
    while n != 0:
        rem = m % n
        m = n
        n = rem
    return m

# in Python3 code there is xrange replaced with range function
def main(a1, a2):
    comp = 0
    for j in xrange(a1, 1, -1):
        for i in xrange(1, a2):
            comp += gcd(i,j)

    print(comp)

if __name__ ==  __main__ :
    if len(argv) != 3:
        stderr.write( usage: {0:s} num1 num2
 .format(argv[0]))
        exit(1)
    else:
        main(int(argv[1]), int(argv[2]))

内容:

def gcd(m, n)
    while n != 0
        rem = m % n
        m = n
        n = rem
    end
    return m
end

def main(a1, a2)
    comp = 0
    a1.downto 2 do
        |j|
        1.upto (a2 - 1) do
            |i|
            comp += gcd(i,j)
        end
    end
    puts comp
end

 if __FILE__ == $0
    if ARGV.length != 2
        $stderr.puts( usage: %s num1 num2  % $0)
        exit(1)
    else
        main(ARGV[0].to_i, ARGV[1].to_i)
    end
end

执行时间测量:

$ time python iter_gcd.py 4000 3000
61356305

real    0m22.890s
user    0m22.867s
sys     0m0.006s

$ python -V
Python 2.6.4


$ time python3 iter_gcd.py 4000 3000
61356305

real    0m18.634s
user    0m18.615s
sys     0m0.009s

$ python3 -V
Python 3.1.2


$ time ruby iter_gcd.rb 4000 3000
61356305

real    0m7.619s
user    0m7.616s
sys     0m0.003s

$ ruby -v
ruby 1.9.2p0 (2010-08-18 revision 29036) [x86_64-linux]

我为什么要取得这样的结果,这是很奇怪的。 我认为,在大多数情况下,CPython语比较快,而MRI和甚至新的Ri.R.1.9语是关于抗逆转录病毒的,但这一“大意”确实令我感到惊讶。

此前,我知道,我可以像分数一样使用专门的图书馆功能。 gcd,但我想比较这些基本和三维语言结构的执行情况。

Did 我错过了什么,或者说,下一代Ruby在高超地区的执行情况有多大改善?

最佳回答

Summary

“由于这一功能,斯图尔特的间接费用远大于赖因的间接费用。

Details

作为一种缩微镜,这实际上对两种语言在适当使用中的表现都说了很多。 和你一样,你也想重新制定方案,以利用沙尔和鲁比的长处,但这确实表明目前沙捞越的弱点之一。 速度差异的根源在于职能称为间接费用。 我进行了几次测试,以说明情况。 详见下文。 关于“灰色”试验,我于2000年使用了两种浓缩参数。

Interpreter: Python 2.6.6
Program type: gcd using function call
Total CPU time: 29.336 seconds

Interpreter: Python 2.6.6
Program type: gcd using inline code
Total CPU time: 13.194 seconds

Interpreter: Python 2.6.6
Program type: gcd using inline code, with dummy function call
Total CPU  time: 30.672 seconds

这告诉我们,它不是由造成大部分时间差异的加权职能进行的计算,而是发挥职能本身的作用。 甲型六氯环己烷

Interpreter: Python 3.1.3rc1
Program type: gcd using function call
Total CPU time: 30.920 seconds

Interpreter: Python 3.1.3rc1
Program type: gcd using inline code
Total CPU time: 15.185 seconds

Interpreter: Python 3.1.3rc1
Program type: gcd using inline code, with dummy function call
Total CPU time: 33.739 seconds

同样,实际计算并不是最大的贡献者,而是职能本身所决定的。 在鲁比拉,职能电话管理费用要小得多。 (说明:我不得不使用比照方案版本的较小参数(200),因为鲁宾·鲁宾确实放慢了实时业绩。 但是,这不影响万国邮联的绩效。

Interpreter: ruby 1.9.2p0 (2010-08-18 revision 29036) [i486-linux]
Program type: gcd using function call
Total CPU time: 21.66 seconds

Interpreter: ruby 1.9.2p0 (2010-08-18 revision 29036) [i486-linux]
Program type: gcd using inline code
Total CPU time: 21.31 seconds

Interpreter: ruby 1.8.7 (2010-08-16 patchlevel 302) [i486-linux]
Program type: gcd using function call
Total CPU time: 27.00 seconds

Interpreter: ruby 1.8.7 (2010-08-16 patchlevel 302) [i486-linux]
Program type: gcd using inline code
Total CPU time: 24.83 seconds

通知表明Ruby 1.8 和1.9 两者都不会因“gcd”功能称呼而遭受很大损失,这种功能称为“在线”形式,其程度大致相同。 鲁比·1.9似乎稍有改善,职能呼吁和在线版本之间差别较小。

因此,对问题的答复是:“由于职能要求波什的间接费用远远大于鲁比。

Code

# iter_gcd -- Python 2.x version, with gcd function call
#             Python 3.x version uses range instead of xrange
from sys import argv,stderr

def gcd(m, n):
    if n > m:
        m, n = n, m
    while n != 0:
        rem = m % n
        m = n
        n = rem
    return m

def main(a1, a2):
    comp = 0
    for j in xrange(a1, 1, -1):
        for i in xrange(1, a2):
            comp += gcd(i,j)
    print(comp)

if __name__ ==  __main__ :
    if len(argv) != 3:
        stderr.write( usage: {0:s} num1 num2
 .format(argv[0]))
        exit(1)
    else:
        main(int(argv[1]), int(argv[2]))

# iter_gcd -- Python 2.x version, inline calculation
#             Python 3.x version uses range instead of xrange
from sys import argv,stderr

def main(a1, a2):
    comp = 0
    for j in xrange(a1, 1, -1):
        for i in xrange(1, a2):
            if i < j:
                m, n = j, i
            else:
                m, n = i, j
            while n != 0:
                rem = m % n
                m = n
                n = rem
            comp += m
    print(comp)

if __name__ ==  __main__ :
    if len(argv) != 3:
        stderr.write( usage: {0:s} num1 num2
 .format(argv[0]))
        exit(1)
    else:
        main(int(argv[1]), int(argv[2]))

# iter_gcd -- Python 2.x version, inline calculation, dummy function call
#             Python 3.x version uses range instead of xrange
from sys import argv,stderr

def dummyfunc(n, m):
    a = n + m

def main(a1, a2):
    comp = 0
    for j in xrange(a1, 1, -1):
        for i in xrange(1, a2):
            if i < j:
                m, n = j, i
            else:
                m, n = i, j
            while n != 0:
                rem = m % n
                m = n
                n = rem
            comp += m
            dummyfunc(i, j)
    print(comp)

if __name__ ==  __main__ :
    if len(argv) != 3:
        stderr.write( usage: {0:s} num1 num2
 .format(argv[0]))
        exit(1)
    else:
        main(int(argv[1]), int(argv[2]))

# iter_gcd -- Ruby version, with gcd function call

def gcd(m, n)
    if n > m
        m, n = n, m
    end
    while n != 0
        rem = m % n
        m = n
        n = rem
    end
    return m
end

def main(a1, a2)
    comp = 0
    a1.downto 2 do
        |j|
        1.upto a2-1 do
            |i|
            comp += gcd(i,j)
        end
    end
    puts comp
end

 if __FILE__ == $0
    if ARGV.length != 2
        $stderr.puts( usage: %s num1 num2  % $0)
        exit(1)
    else
        main(ARGV[0].to_i, ARGV[1].to_i)
    end
end

# iter_gcd -- Ruby version, with inline gcd

def main(a1, a2)
    comp = 0
    a1.downto 2 do |j|
        1.upto a2-1 do |i|
            m, n = i, j
            if n > m
                m, n = n, m
            end
            while n != 0
                rem = m % n
                m = n
                n = rem
            end
            comp += m
        end
    end
    puts comp
end

 if __FILE__ == $0
    if ARGV.length != 2
        $stderr.puts( usage: %s num1 num2  % $0)
        exit(1)
    else
        main(ARGV[0].to_i, ARGV[1].to_i)
    end
end

Test runs

最后,为了比较数字而用于Palileo和Ruby的指挥系统是:pythonX.X -m cProfile iter_gcdX.py 2000,用于“Zal”和rubyX.X.rprofile iter_gcdX.rb 200。 出现差异的原因是,Ruby的简介员增加了很多间接费用。 成果仍然有效,因为我对职能呼吁和在线编码之间的区别进行对比,而不是将沙尔和鲁比之间的区别进行比较。

See also

为什么比鲁比如此简单的“测试”更慢?

这部法律是否有错误,为什么与废墟相比如此缓慢?

The Computer Language Benchmarks Game

页: 1

问题回答

我似乎记得,废墟处理的是不同的愤怒,因此,我的猜测就是说,花在很多时间分配记忆,而鲁比拉只是mut平现有的愤怒。

就价值而言,用Pypy 1.4将Zahury版本的操作时间从大约15秒减少到3秒以下。

我可以重复你的成果。 p法似乎比 rub法高4倍:

2010-12-07 13:49:55:~/tmp$ time python  iter_gcd.py 4000 3000
61356305

real    0m14.655s
user    0m14.633s
sys 0m0.012s

2010-12-07 13:43:26:~/tmp$ time ruby iter_gcd.rb 4000 3000
iter_gcd.rb:14: warning: don t put space before argument parentheses
61356305

real    0m54.298s
user    0m53.955s
sys 0m0.028s

版本:

2010-12-07 13:50:12:~/tmp$ ruby --version
ruby 1.8.7 (2010-06-23 patchlevel 299) [i686-linux]
2010-12-07 13:51:52:~/tmp$ python --version
Python 2.6.6

此外, p法可以更快地达到8%:

def gcd(m, n):
    if n > m:
        m, n = n, m
    while n:
        n, m = m % n, n
    return m

def main(a1, a2):
    print sum(
        gcd(i,j)
        for j in xrange(a1, 1, -1)
        for i in xrange(1, a2)
    )

if __name__ ==  __main__ :
    from sys import argv
    main(int(argv[1]), int(argv[2]))

后来:当我安装和使用1.9.1的废墟时,废墟法典越快:

2010-12-07 14:01:08:~/tmp$ ruby1.9.1 --version
ruby 1.9.2p0 (2010-08-18 revision 29036) [i686-linux]
2010-12-07 14:01:30:~/tmp$ time ruby1.9.1 iter_gcd.rb 4000 3000
61356305

real    0m12.137s
user    0m12.037s
sys 0m0.020s

我认为,你的问题确实是,“Why is Mouy 1.9.x so要快于1.8.x?”





相关问题
Can Django models use MySQL functions?

Is there a way to force Django models to pass a field to a MySQL function every time the model data is read or loaded? To clarify what I mean in SQL, I want the Django model to produce something like ...

An enterprise scheduler for python (like quartz)

I am looking for an enterprise tasks scheduler for python, like quartz is for Java. Requirements: Persistent: if the process restarts or the machine restarts, then all the jobs must stay there and ...

How to remove unique, then duplicate dictionaries in a list?

Given the following list that contains some duplicate and some unique dictionaries, what is the best method to remove unique dictionaries first, then reduce the duplicate dictionaries to single ...

What is suggested seed value to use with random.seed()?

Simple enough question: I m using python random module to generate random integers. I want to know what is the suggested value to use with the random.seed() function? Currently I am letting this ...

How can I make the PyDev editor selectively ignore errors?

I m using PyDev under Eclipse to write some Jython code. I ve got numerous instances where I need to do something like this: import com.work.project.component.client.Interface.ISubInterface as ...

How do I profile `paster serve` s startup time?

Python s paster serve app.ini is taking longer than I would like to be ready for the first request. I know how to profile requests with middleware, but how do I profile the initialization time? I ...

Pragmatically adding give-aways/freebies to an online store

Our business currently has an online store and recently we ve been offering free specials to our customers. Right now, we simply display the special and give the buyer a notice stating we will add the ...

Converting Dictionary to List? [duplicate]

I m trying to convert a Python dictionary into a Python list, in order to perform some calculations. #My dictionary dict = {} dict[ Capital ]="London" dict[ Food ]="Fish&Chips" dict[ 2012 ]="...