Board logo

标题: [原创教程] Perl 内嵌 C 代码 [打印本页]

作者: 523066680    时间: 2017-8-4 22:25     标题: Perl 内嵌 C 代码

本帖最后由 523066680 于 2017-8-5 08:23 编辑

在优化猜数字游戏脚本的运行效率时(其实是在看Imager模块的示例偶然发现),发现了 Perl 可以内联 C 代码,可以极大地提高效率。
原本跑完5040次猜数字测试,用 perl 写的test函数消耗(累积)可能需要10秒,现在只需要零点几秒。
  1. use IO::Handle;
  2. use Inline C;
  3. STDOUT->autoflush(1);
  4. my $nums = "4109";
  5. my $guess = "0124";
  6. my $AB = "00";
  7. for (1..5)
  8. {
  9. $AB = "00";
  10. test($nums, $guess, $AB);
  11. print "$AB\n";
  12. }
  13. __END__
  14. __C__
  15. void test(char *stra, char *strb, char *AB)
  16. {
  17.     int idx;
  18.     for ( idx = 0; idx < 4; idx++ )
  19.     {
  20.         if ( stra[idx] == strb[idx] )
  21.             AB[0]++;
  22.         else
  23.             if ( strchr(stra, strb[idx]) != 0 )
  24.             {
  25.                 AB[1]++;
  26.             }
  27.     }
  28. }
复制代码
不过以上代码有个问题,就是 $AB = "00" 的重置无效了,每次结果都会被递增,输出如下
  1. 12
  2. 24
  3. 36
  4. 48
  5. 5:
复制代码
所以C函数部分重写,用临时变量从 '0' 开始计数。(为了统一,我用的是字符'0' )
  1. __END__
  2. __C__
  3. void bullcow(char *stra, char *strb, char *AB)
  4. {
  5.     int idx;
  6.     char a = '0';
  7.     char b = '0';
  8.     for ( idx = 0; idx < 4; idx++ )
  9.     {
  10.         if ( stra[idx] == strb[idx] )
  11.             a++;
  12.         else
  13.             if ( strchr(stra, strb[idx]) != 0 )
  14.             {
  15.                 b++;
  16.             }
  17.     }
  18.     AB[0] = a;
  19.     AB[1] = b;
  20. }
复制代码

作者: codegay    时间: 2017-8-5 01:47


__END__
写在最上面吗?这逻辑我没法懂啊。
作者: 523066680    时间: 2017-8-5 08:08

本帖最后由 523066680 于 2017-8-5 14:44 编辑

回复 2# codegay

    __END__ 在 perl 里面表示脚本结束的节点,可以放备注、数据之类的信息。
作者: 523066680    时间: 2017-8-5 08:57     标题: 效率对比

本帖最后由 523066680 于 2017-8-5 09:08 编辑

时间占用对比,用 Devel::NYTProf 模块分析效率
perl -d:NYTProf normal.pl
nytprofhtml


perl -d:NYTProf InlineC.pl
nytprofhtml


两份完整的测试代码:
  1. use IO::Handle;
  2. STDOUT->autoflush(1);
  3. my $nums = "4109";
  4. my $guess = "0124";
  5. my $AB = "00";
  6. for ( 1 .. 100000 )
  7. {
  8.     $AB = "00";
  9.     bullcow($nums, $guess, \$AB);
  10.     print "$AB\n";
  11. }
  12. sub bullcow
  13. {
  14.     my ($nums, $guess, $AB) = @_;
  15.     my ($A, $B) = (0, 0);
  16.     my $t;
  17.     for my $i ( 0 .. 3 )
  18.     {
  19.         if ( substr($nums, $i, 1) eq substr($guess, $i, 1) )
  20.         {
  21.             $A++;
  22.         }
  23.         else
  24.         {
  25.             $t = substr($guess, $i, 1);
  26.             $B++ if ( $nums =~/$t/ );
  27.         }
  28.     }
  29.     $$AB = "$A$B";
  30. }
复制代码
内联C的版本:
  1. use Inline C;
  2. use IO::Handle;
  3. STDOUT->autoflush(1);
  4. my $nums = "4109";
  5. my $guess = "0124";
  6. my $AB = "00";
  7. for ( 1 .. 100000 )
  8. {
  9.     $AB = "00";
  10.     bullcow($nums, $guess, $AB);
  11.     print "$AB\n";
  12. }
  13. __END__
  14. __C__
  15. void bullcow(char *stra, char *strb, char *AB)
  16. {
  17.     int idx;
  18.     char a = '0';
  19.     char b = '0';
  20.     for ( idx = 0; idx < 4; idx++ )
  21.     {
  22.         if ( stra[idx] == strb[idx] )
  23.             a++;
  24.         else
  25.             if ( strchr(stra, strb[idx]) != 0 )
  26.             {
  27.                 b++;
  28.             }
  29.     }
  30.     AB[0] = a;
  31.     AB[1] = b;
  32. }
复制代码

作者: codegay    时间: 2017-8-5 14:40

我对perl完全不懂哦。
作者: Wiki    时间: 2018-9-23 00:10

提高效率啊。




欢迎光临 批处理之家 (http://bathome.net./) Powered by Discuz! 7.2