2008-01
29

上周偶然与fcicq讨论到一个关于perlcc的优化问题。 据说用perlcc将perl程序编译成C程序后再用gcc -O3进行优化,速度可能会快一些。 于是就测了测,顺便试了试其他语言的情况。

测试程序是Ackermann函数。 也许用它来做benchmark不太合适,但毕竟这是个纯数学+多次递归+耗时的运算,也能反映一定问题吧。

先来看Perl的原版。

$ cat ack.pl
#!/usr/bin/perl

sub ackermann {
  my ( $m, $n ) = @_;

  return $n + 1 if $m == 0;
  return ackermann( $m - 1, 1 ) if $n == 0;
  return ackermann( $m - 1, ackermann( $m, $n - 1 ) );
}

print ackermann( 3, 10 ), "\n";

$ time ./ack.pl
8189

real    1m5.044s
user    1m4.412s
sys     0m0.620s

结果约为65秒。然后用perlcc编译并gcc -O3优化试试:

$ cp /usr/lib/perl5/5.8.8/i386-linux-thread-multi/auto/DynaLoader/DynaLoader.a .
$ ar xv DynaLoader.a          # 先弄个必要的DynaLoader.o否则会连接错误
$ perl -c -o ack-perlcc.c ack.pl
$ gcc -O3 -c -o ack-perlcc.o `perl -MExtUtils::Embed -e ccopts` ack-perlcc.c
$ gcc -o ack-perlcc `perl -MExtUtils::Embed -e ldopts` DynaLoader.o ack-perlcc.o
$ time ./ack-perlcc
8189
real    1m3.487s
user    1m3.012s
sys     0m0.484s

用了63秒,跟perl是同一数量级的。可见这个perlcc之后没什么效果。

遗憾之余顺手写了个纯C版本:

$ cat myack.c
#include <stdio.h>

int ackermann(int m, int n);

int main() {
  int result = ackermann(3, 10);
  printf("%d\n", result);
  return 0;
}

int ackermann(int m, int n) {
  if (m == 0) return n+1;
  if (n == 0) return ackermann(m-1, 1);
  return ackermann(m-1, ackermann(m, n-1));
}

$ gcc -O3 -o myack myack.c
$ time ./myack
8189

real    0m0.231s
user    0m0.228s
sys     0m0.004s

哇!0.23秒,比perl语言快了280倍以上。看来谈到效率时果然C语言才是王道。 也难怪为什么C程序员的待遇那么高了。

当然这个程序是纯粹的数学运算,发挥不出perl的长处,才会让perl效率如此低吧。

PHP也有同样的问题。还是这个Ackermann函数,用纯PHP写出来的效率很低, 但如果将函数写成php extension再调用,效率几乎等同于C语言的效率。 于是得出个结论,复杂的算法还是不要用PHP直接实现,而是写成extension吧。




这篇文章有 6 条评论了,快来一起讨论讨论吧!
#1
fcicq
2008-01-29 18:39

$ gcc -c -o ack-perlcc.o `perl -MExtUtils::Embed -e ccopts` ack-perlcc.c —- ms 应该在这个地方 O3…快改快改…

#2
fcicq
2008-01-29 19:55

试了,好像差不多… :(

#3
charlee
2008-01-30 14:46

谢谢,改过来了

#4
Yurii
2008-02-04 00:37

Perl的“效率”不光是执行的效率,开发也有效率的咯:)

#5
charlee
2008-02-04 09:36

@Yurii 的确——高级语言可以说就是用执行效率换取开发效率,毕竟现在硬件要比人工便宜多了。从这个角度来说,员工培训实际上就是在提高开发效率。

#6
fcicq
2008-04-05 21:18

测试了一下 microperl, ack(3,7), perl 0.8s, microperl 更慢, 1.1s.

添加评论