为什么我的Python版本比我的Perl版本慢?

Foo*_*baz 13 python perl performance

我已经是一个超过10年的Perl家伙,但是一位朋友说服我尝试使用Python并告诉我它比Perl快多少.所以只是为了踢,我把我用Perl编写的应用程序移植到Python中,发现它运行速度慢了3倍.最初,我的朋友告诉我,我一定做错了,所以我重写并重构,直到我不能重写和重构......它仍然慢得多.所以我做了一个简单的测试:

i = 0
j = 0

while (i < 100000000):
    i = i + 1
    j = j + 1

print j
Run Code Online (Sandbox Code Playgroud)

$ time python python.py
100000000

真正的0m48.100s
用户0m45.633s
sys 0m0.043s

my $i = 0;
my $j = 0;

while ($i < 100000000) {
    ++$i; # also tested $i = $i + 1 to be fair, same result
    ++$j;
}

print $j;
Run Code Online (Sandbox Code Playgroud)

$ time perl perl.pl
100000000

实际0m24.757s
用户0m22.341s
sys 0m0.029s

慢了两倍,这似乎没有反映出我见过的任何基准测试......我的安装有问题还是Python真的比Perl慢得多

Ben*_*kin 51

挑剔的答案是你应该将它与惯用的Python进行比较:

  • 原始代码在我的机器上需要34秒.
  • 一个for循环(FlorianH的答案),与+=xrange()21.
  • 将整个功能放在一个功能中将其减少到9秒!
    这比Perl快得多(在我的机器上15秒)!
    说明:Python本地变量比全局变量快得多.
    (为了公平起见,我也在Perl中尝试了一个函数 - 没有变化)
  • 摆脱j变量将其减少到8秒:

    print sum(1 for i in xrange(100000000))

Python具有奇怪的属性,更高级别的更短代码往往是最快的:-)

但真正的答案是你的"微观基准"毫无意义.语言速度的真正问题是:平均实际应用程序的性能如何?要知道这一点,你应该考虑到:

  • 复杂代码中典型的操作组合.您的代码不包含任何数据结构,函数调用或OOP操作.

  • 足够大的代码库可以感受缓存效果 - 许多解释器优化会为了速度而交换内存,而任何微小的基准都无法公平地衡量.

  • 优化 机会:在您编写代码后,如果速度不够快,您可以轻松实现多快?

    例如,将繁重的工作卸载到有效的C libriries有多难?

PyPy的基准测试Octane是现实语言速度基准测试的好例子.

如果你想谈论数字运算,Python的IS与科学家令人惊讶的流行.他们喜欢简单的伪数学语法和简短的学习曲线,但也喜欢用于数组运算的优秀numpy库以及包装其他现有C代码的简易性.

然后有Psyco JIT可能会在1秒内运行你的玩具示例,但我现在无法检查它,因为它只适用于32位x86.
编辑:现在,跳过Psyco并使用PyPy,这是一个跨平台积极改进JIT.

  • +1:你的"微观基准"毫无意义 - 并且更多地揭示了基准的作者,而不是基准的语言. (6认同)
  • 我认为它是python中的一个缺点,它使变量存在的奇怪方式不允许你没有函数的"局部变量":) (2认同)

dra*_*tun 8

所有这些微观基准测试都会变得有点傻!

例如.只需for在Python和Perl中切换,就可以提供巨大的速度提升.如果使用原始Perl示例将快两倍for:

my $j = 0;

for my $i (1..100000000) {
    ++$j;
}

print $j;
Run Code Online (Sandbox Code Playgroud)


我可以用这个来削减一点:

++$j for 1..100000000;
print $j;
Run Code Online (Sandbox Code Playgroud)


变得更傻了我们可以把它降到1秒;-)

print {STDOUT} (1..10000000)[-1];
Run Code Online (Sandbox Code Playgroud)

/ I3az /

ref:使用Perl 5.10.1.


Nou*_*him 7

Python在数值计算方面并不是特别快,我确信它在文本处理方面比perl慢.

既然你是一个经验丰富的Perl手,我不知道这是否适用于你,但从长远来看Python程序往往更易于维护并且开发速度更快.对于大多数情况来说,速度"足够",当您真正需要提升性能时,您可以灵活地降低到C级.

更新

好的.我刚刚创建了一个包含随机数据的大文件(1GB)(主要是ascii)并将其分成相等长度的行.这应该是模拟日志文件.

然后我运行简单的perl和python程序,逐行搜索文件以获得现有模式.

使用Python 2.6.2,结果是

real    0m18.364s
user    0m9.209s
sys 0m0.956s
Run Code Online (Sandbox Code Playgroud)

并使用Perl 5.10.0

real    0m17.639s
user    0m5.692s
sys 0m0.844s
Run Code Online (Sandbox Code Playgroud)

程序如下(如果我做了一些愚蠢的事,请告诉我)

import re
regexp = re.compile("p06c")

def search():
    with open("/home/arif/f") as f:
        for i in f:
            if regexp.search(i):
                print "Found : %s"%i

search()
Run Code Online (Sandbox Code Playgroud)

sub search() {
  open FOO,"/home/arif/f" or die $!;
  while (<FOO>) {
    print "Found : $_\n" if /p06c/o;
  }
}

search();
Run Code Online (Sandbox Code Playgroud)

结果非常接近并以这种方式调整或其他似乎不会改变结果.我不知道这是否是一个真正的基准,但我认为这是我用两种语言搜索日志文件的方式,所以我对相对表现进行了纠正.

谢谢克里斯.

  • "从长远来看,Python程序往往更易于维护,而且开发速度更快." [citation needed](Python甚至不允许你预先声明变量.在赋值期间有一个拼写错误,你有一个很难找到的bug.) (11认同)
  • 如果你是Perl-illiterate,Python只会更具可读性.;) (7认同)
  • 我不同意"它在文本处理方面比perl慢"声明.在你这么说之前,你应该提供自己的基准测试来证明理由 (5认同)
  • "我希望它更快,我认为就是这种情况." 那么,不要介意提供证据吧!期望和预感几乎从未被证明是错误的. (3认同)
  • 如果它有帮助 - 语言枪战通常显示python在正则表达式测试中花费两倍于perl的平均时间.http://shootout.alioth.debian.org/u32q/python.php (3认同)
  • 在许多平台上,旧的perl会做得更好; 从5.10开始,usefaststdio(以前是许多平台上的默认设置 - 这导致perl尝试以封装破解的方式与libc的FILE结构进行交互以实现盲目速度)默认为关闭,较慢的perlio抽象层取代了stdio的使用. (3认同)
  • @steveha:我没有看到任何我称之为狙击的评论,除非过于简单的"基准",不管语言如何. (2认同)

Flo*_*anH 7

如果你使用python语言的正确语法,Python运行速度非常快.它大致被描述为" pythonic ".

如果像这样重构代码,它的运行速度至少要快两倍(好吧,它在我的机器上运行):

j = 0
for i in range(10000000):
    j = j + 1
print j
Run Code Online (Sandbox Code Playgroud)

每当你在python中使用while时,你应该检查你是否也可以使用"for X in range()".

  • 通常,使用螺丝刀拧紧螺钉和钉锤是工具使用者的正常行为. (2认同)

gho*_*g74 7

对于OP,在Python中这段代码:

j = 0
for i in range(10000000):
    j = j + 1
print j
Run Code Online (Sandbox Code Playgroud)

是相同的

print range(10000001)[-1]
Run Code Online (Sandbox Code Playgroud)

在我的机器上,

$ time python test.py
10000000

real    0m1.138s
user    0m0.761s
sys     0m0.357s
Run Code Online (Sandbox Code Playgroud)

运行大约1秒.range()(或xrange)是Python的内部和"内部",它已经可以为你生成一系列数字.因此,您不必使用自己的循环创建自己的迭代.现在,你去找一个可以运行1秒的Perl等价物来产生相同的结果

  • 你正在减少已经玩具的例子ad absurdum.在这条道路上,perl等价物将是"print 100000000;". (9认同)
  • @Beni Cherniavsky-Paskin:由于'print 10000000`是perl例子的净效应,这是对这个基准的一个非常可靠的起诉.也许来自Project Euler的东西可能是更好的选择. (4认同)
  • 我的是1亿,有8个零而不是7. (2认同)
  • @Beni,我相信你知道使用print 100000000对于这个玩具例子来说毫无意义.我的例子展示了如何在Python中为"不使用循环"获得相同结果的"循环",至少不是明确的 (2认同)
  • 找一个perl等价物?像'foreach $ i(1..10000000){...}`这样的东西?或者`打印[1..10000000] - > [ - 1]`?是的,Perl也有数字范围. (2认同)

rob*_*rob 5

Python 在字典中维护全局变量。因此,每次有赋值时,解释器都会在模块字典中执行查找,这有点昂贵,这就是您发现示例如此慢的原因。

为了提高性能,您应该使用本地分配,就像创建函数一样。Python解释器将局部变量存储在数组中,访问速度更快。
但是,应该注意的是,这是一个实现细节CPython的例如,我怀疑 IronPython 会导致完全不同的结果。

最后,有关此主题的更多信息,我建议您阅读 GvR 中有关 Python 优化的有趣文章:Python 模式 - 优化轶事