Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance 为什么要替换Perl';s///使用内联::C的伪函数会导致显著的速度减慢吗?_Performance_Perl_Inline C - Fatal编程技术网

Performance 为什么要替换Perl';s///使用内联::C的伪函数会导致显著的速度减慢吗?

Performance 为什么要替换Perl';s///使用内联::C的伪函数会导致显著的速度减慢吗?,performance,perl,inline-c,Performance,Perl,Inline C,我有一个大约100000个元素的字符串数组。我需要遍历每个元素并用其他单词替换一些单词。这在纯perl中需要几秒钟的时间。我需要尽可能加快速度。我正在使用以下代码段进行测试: 使用严格; my$string=“这是一些字符串。它的唯一用途是测试。”; 对于(我的$i=1;$i\&Pure\u Perl, “内联C”=>\&内联C } ); 亚纯perl{ my$string=“这是一些字符串。它的唯一用途是测试。”; 对于(我的$i=1;$i

我有一个大约100000个元素的字符串数组。我需要遍历每个元素并用其他单词替换一些单词。这在纯perl中需要几秒钟的时间。我需要尽可能加快速度。我正在使用以下代码段进行测试:

使用严格;
my$string=“这是一些字符串。它的唯一用途是测试。”;
对于(我的$i=1;$i<100000;$i++){
$string=~s/old1/new1/ig;
$string=~s/old2/new2/ig;
$string=~s/old3/new3/ig;
$string=~s/old4/new4/ig;
$string=~s/old5/new5/ig;
}
我知道这实际上并不能代替测试字符串中的任何内容,但它只是用于速度测试

我满怀希望。我以前从未使用过
Inline::C
,但在读了一点之后,我认为它的实现相当简单。但显然,即使调用一个不做任何事情的存根函数也要慢得多。以下是我测试的代码片段:

使用严格;
使用基准qw(这些时间);
使用内联'C';
时间这些(
5.
{
“纯Perl”=>\&Pure\u Perl,
“内联C”=>\&内联C
}
);
亚纯perl{
my$string=“这是一些字符串。它的唯一用途是测试。”;
对于(我的$i=1;$i<1000000;$i++){
$string=~s/old1/new1/ig;
$string=~s/old2/new2/ig;
$string=~s/old3/new3/ig;
$string=~s/old4/new4/ig;
$string=~s/old5/new5/ig;
}
}
子单元c{
my$string=“这是一些字符串。它的唯一用途是测试。”;
对于(我的$i=1;$i<1000000;$i++){
$string=findreplace($string,“old1”,“new1”);
$string=findreplace($string,“old2”,“new2”);
$string=findreplace($string,“old3”,“new3”);
$string=findreplace($string,“old4”,“new4”);
$string=findreplace($string,“old5”,“new5”);
}
}
__资料__
__C__
煤焦*
findreplace(字符*文本,字符*内容,字符*带){
返回文本;
}
在我的Linux机器上,结果是:

Benchmark: timing 5 iterations of Inline C, Pure Perl...
  Inline C:  6 wallclock secs ( 5.51 usr +  0.02 sys =  5.53 CPU) @  0.90/s (n=5)
  Pure Perl:  2 wallclock secs ( 2.51 usr +  0.00 sys =  2.51 CPU) @  1.99/s (n=5)

纯Perl的速度是调用空C函数的两倍。完全不是我所期望的!同样,我以前从未使用过内联::C,所以可能我在这里遗漏了什么?

在使用
Inline::C
的版本中,您保留了原始纯Perl脚本中的所有内容,只更改了一件事:此外,您用更糟糕的实现替换了Perl高度优化的
s/
。调用您的伪函数实际上需要做很多工作,而在这种情况下,
s//
调用都做不了多少工作。对于
Inline::C
版本来说,运行得更快是不可能的

在C端,函数

char *
findreplace( char *text, char *what, char *with ) {

  return text;

}
不是“什么都不做”的功能。调用它需要解包参数。必须将
text
指向的字符串复制到返回值。每次调用都要支付一些开销

鉴于
s//
没有替代品,因此不涉及复制。此外,Perl的
s///
经过了高度优化。你确定你能写一个更好的查找和替换程序来弥补调用外部函数的开销吗

如果使用以下实现,您应该可以获得类似的速度:

sub inline_c {
  my $string = "This is some string. It's only purpose is for testing.";
  for( my $i = 1; $i < 1000000; $i++ ) {
    findreplace( $string );
    findreplace( $string );
    findreplace( $string );
    findreplace( $string );
    findreplace( $string );
  }
}

__END__
__C__

void findreplace( char *text ) {
    return;

}

在这种情况下,每次调用
find_和_replace
大约需要2.3秒。这五次复制大约在30秒内完成。开销是生成1000000个句子数据集并复制四次的综合成本。

在我的机器上,使用Perl 5.20.1,C需要5秒,Perl需要4秒。这表明这样的基准是多么的毫无意义。特别是如果您的开发机器不是生产系统,这就是我在生产机器的克隆上开发的原因。:)也许有更好的解决办法。你能告诉我们实际的代码吗?你想要多快?“尽我所能”并不是一个真正的目标。假设读取输入数据需要10秒,替换需要2秒。如果将替换所需的时间缩短到半秒,则脚本的运行时间将从12秒缩短到10.5秒,在脚本的这一部分提高75%的基础上,总体执行时间将提高12.5%。对于初学者来说,Perl子例程调用相当昂贵。我同意这不是一个“什么都不做”的函数。但我需要编写一个真正的查找和替换函数。因此真正的函数总是比这个慢。Re“Perl的///是高度优化的”,特别是当模式不匹配时。 Benchmark: timing 5 iterations of Inline C, Pure Perl... Inline C: 6 wallclock secs ( 5.69 usr + 0.00 sys = 5.69 CPU) @ 0.88/s (n=5) Pure Perl: 6 wallclock secs ( 5.70 usr + 0.00 sys = 5.70 CPU) @ 0.88/s (n=5)
#!/usr/bin/env perl

use warnings;
use strict;

use Data::Fake::Text;
use List::Util qw( sum );
use Time::HiRes qw( time );

use constant INPUT_SIZE => $ARGV[0] // 1_000_000;

run();

sub run {
    my @substitutions = (
        sub { s/dolor/new1/ig   },
        sub { s/fuga/new2/ig    },
        sub { s/facilis/new3/ig },
        sub { s/tempo/new4/ig   },
        sub { s/magni/new5/ig   },
    );

    my @times;
    for (1 .. 5) {
        my $data = read_input();
        my $t0 = time;
        find_and_replace($data, \@substitutions);
        push @times, time - $t0;
    }

    printf "%.4f\n", sum(@times)/@times;

    return;
}

sub find_and_replace {
    my $data = shift;
    my $substitutions = shift;

    for ( @$data ) {
        for my $s ( @$substitutions ) {
            $s->();
        }
    }
    return;
}

{
    my @input;
    sub read_input {
        @input
            or @input = map fake_sentences(1)->(), 1 .. INPUT_SIZE;
        return [ @input ];
    }
}