2009-11-03 4 views
2

이들 중 어느 것이 더 저렴합니까? perldoc perlvar에서

$_ = 'abc123def'; 

s/\d+/$&*2/e; 
say; 

s/(\d+)/$1*2/e; 
say; 
+2

왜 신경 써야합니까? 큰 파일을 파싱하고 있습니까? – ghostdog74

+0

왜 'e'한정자가 필요합니까? –

+1

대체면에서 해당 식을 계산하려면/e가 필요합니다. :) –

답변

11

요약 요약 : 대신 5.010의/p를 사용하십시오. $&의 성능은 단일 일치 또는 대체에 대해 거의 같음 이지만 전체 프로그램 이 영향을받을 수 있습니다.속도가 느린 것은 지역이 아닌 장거리입니다.


는 여기에 내가 거기에 say이 있기 때문에 사용하는 의심 5.010과 벤치 마크입니다. 5.010에는 $&처럼 작동하지만 일치 또는 대체 연산자의 인스턴스가 하나만있는 ${^MATCH} 변수를 제공하는 새로운 /p 플래그가 있습니다.

벤치 마크와 마찬가지로 기준점을 설정하는 컨트롤과 비교하여 지루한 비트가 얼마나 많은 시간을 차지하는지 알 수 있습니다. 또한이 벤치 마크에는 함정이 있습니다. 코드에서 $&을 사용할 수 없거나 모든 대체가 어렵습니다. 먼저 $& 하위없이 벤치 마크를 실행

use 5.010; 

use Benchmark qw(cmpthese); 

cmpthese(1_000_000, { 
    'control' => sub { my $_ = 'abc123def'; s/\d+/246/ }, 
    'control-e' => sub { my $_ = 'abc123def'; s/\d+/123*2/e; }, 
    '/p'  => sub { my $_ = 'abc123def'; s/\d+/${^MATCH}*2/pe }, 
    # '$&'  => sub { my $_ = 'abc123def'; s/\d+/$&*2/e }, 
    '()'  => sub { my $_ = 'abc123def'; s/(\d+)/$1*2/e }, 
}); 

을 내 맥북 에어 실행 레오파드와 바닐라 펄 5.10에 :

   Rate  /p  () control-e control 
/p   70621/s  --  -1%  -58%  -78% 
()   71124/s  1%  --  -58%  -78% 
control-e 168350/s  138%  137%  --  -48% 
control 322581/s  357%  354%  92%  -- 

을 주목 /e 옵션으로 큰 침체, 난 그냥 추가 한 낄낄 거림. /p 여기 을 shihe 것 같다 있지만,

지금, 나는 $& 지점의 주석거야, 나는 모든 것이 느린 것을 볼 :

   Rate  ()  $&  /p control-e control 
()   68353/s  --  -4%  -7%  -58%  -74% 
$&   70872/s  4%  --  -3%  -56%  -73% 
/p   73421/s  7%  4%  --  -54%  -72% 
control-e 161290/s  136%  128%  120%  --  -39% 
control 262467/s  284%  270%  257%  63%  -- 

이 이상한 벤치 마크입니다. control-e sub가 포함되지 않은 경우 상황이 다르게 보입니다. 이는 벤치마킹의 또 다른 개념을 보여줍니다. 절대적이지 않고 모든 것이 최종 결과에서 중요합니다. 이 실행에서, $&은 약간 빠른 같습니다

  Rate  ()  /p  $& control 
()  69686/s  --  -3%  -3% -72% 
/p  72098/s  3%  --  -0% -71% 
$&  72150/s  4%  0%  -- -71% 
control 251256/s 261% 248% 248%  -- 

을 그래서, 나는 다시 control-e 그것을 실행하고, 결과는 약간의 주위에 이동 : 각

   Rate  ()  /p  $& control-e control 
()   68306/s  --  -3%  -4%  -55%  -74% 
/p   70175/s  3%  --  -1%  -54%  -73% 
$&   71023/s  4%  1%  --  -53%  -73% 
control-e 151976/s  122%  117%  114%  --  -41% 
control 258398/s  278%  268%  264%  70%  -- 

속도 차이 중 하나 인상적하지 않습니다 . 그 차이는 sub에 대한 반복 호출을 통해 오류가 누적되기 때문에 약 7 % 미만의 값은 그다지 중요하지 않습니다 (같은 코드를 자체적으로 벤치마킹하여 언젠가 시도하십시오). 약간의 차이는 벤치마킹 인프라에서 비롯된 것입니다. 이 숫자를 사용하면 각 기술은 속도면에서 거의 동일합니다. 한 번 벤치 마크를 실행할 수는 없습니다. 반복 가능한 결과가 나오는지 보려면 여러 번 실행해야합니다.

/p이 다소 느리게 보이지만, $&은 모두를 망쳐 놓기 때문에 더 느립니다. 컨트롤의 속도가 너무 느려집니다. 이것이 벤치마킹이 매우 위험한 이유 중 하나입니다. 왜 그들이 틀렸는가에 대해 열심히 생각하지 않는다면 결과를 오도 할 수 있습니다. (전체 장의 내용은 Mastering Perl입니다.)

이 단순하고 순진한 벤치 마크에서는 킬러가 제외됩니다 그러나 $&의 기형입니다. 추가적인 일치를 처리하기 위해 벤치 마크를 수정합시다.첫째, 내가 $&가 추가 경기 연산자에 약 1,000 문자를 복사해야 상황을 건설 한 어떤 $& 효과와 기준 :

use 5.010; 

use Benchmark qw(cmpthese); 

$main::long = ('a' x 1_000) . '123' . ('b' x 1_000); 

cmpthese(1_000_000, { 
    'control' => sub { my $_ = 'abc123def'; s/\d+/246/; $main::long =~ m/^a+123/; }, 
    'control-e' => sub { my $_ = 'abc123def'; s/\d+/123*2/e; $main::long =~ m/^a+123/; }, 
    '/p'  => sub { my $_ = 'abc123def'; s/\d+/${^MATCH}*2/pe; $main::long =~ m/^a+123/; }, 
    #'$&'  => sub { my $_ = 'abc123def'; s/\d+/$&*2/e; $main::long =~ m/^a+123/;}, 
    '()'  => sub { my $_ = 'abc123def'; s/(\d+)/$1*2/e; $main::long =~ m/^a+123/; }, 
}); 

모든 것이 이전보다 훨씬 느립니다,하지만 그 때 발생하는 상황 당신이 더 많은 일을하고, 두 기술은 서로의 소음 내에 다시 :

   Rate  ()  $&  /p control-e control 
()   50607/s  --  -1%  -3%  -43%  -59% 
$&   50968/s  1%  --  -2%  -43%  -58% 
/p   52274/s  3%  3%  --  -41%  -57% 
control-e 89206/s  76%  75%  71%  --  -27% 
control 122100/s  141%  140%  134%  37%  -- 
: 이제

   Rate  ()  /p control-e control 
()   52826/s  --  -4%  -49%  -63% 
/p   54885/s  4%  --  -47%  -61% 
control-e 103734/s  96%  89%  --  -27% 
control 141243/s  167%  157%  36%  -- 

, 나는 $& 하위의 주석3210

그 결과는 매우 흥미 롭습니다. 이제 /p은 여전히 ​​$&의 부정 행위로 불이익을 받았지만 모두가 크게 고통을 겪고 있지만 (소음이 있지만) 약간 빨라졌습니다.

다시 말하지만 이러한 결과에 매우주의하십시오. 이것은 모든 스크립트에 대해 $&이 동일한 효과를 갖음을 의미하지는 않습니다. 일치 횟수, 특정 정규식 등에 따라 속도가 느려지거나 그 이상이 될 수 있습니다. 벤치 마크가 보여주는 것은 아이디어가 아니라 결정입니다. 이 아이디어가 특정 상황에 어떻게 영향을 미치는지 파악해야합니다.

+1

+1 멋진 벤치! – sebthebert

10

:

  • $ 매치
  • $ &

마지막으로 성공한 패턴 일치 일치 문자열의 (a BLOCK 안에 숨겨진 어떤 일치를 계산하지 않거나 eval()은 현재 BLOCK으로 묶여 있음) . (니모닉 : 일부 편집기에서는 &과 같습니다.)이 변수는 읽기 전용이며 현재 BLOCK까지 동적으로 범위가 지정됩니다.

프로그램에서이 변수를 사용하면 모든 정규 표현식 일치에서 상당한 성능 저하가 발생합니다. "BUGS"을 참조하십시오.

대체하려면 "@-"을 참조하십시오.

이 정보가 설명서에 편리하지 않더라도 여전히 시간을내어 확인할 수 있습니다.

+6

각 인스턴스의 수십만 개의 인스턴스에 대한 순진 테스트가 '$ &'는 그룹화보다 약간 빠르다는 것을 보여줍니다. 그러나 문서에서 말하는 것처럼'$ &'_at all_를 사용하면 _all_ regexes가 느려지지만 괄호를 사용하면 괄호를 사용하는 정규식의 속도가 느려지 게됩니다. –

0
use Benchmark; 

및 테스트.

일반적으로 - 실제로, 정말로 중요하지 않습니다. 이러한 작업을 수십억을하지 않는 한.

+1

이 경우 중요합니다. '$ &'는 스크립트/프로그램에서 모든 정규식을 느리게 만듭니다. – innaM

+1

... 보통의 time_these 함수를 사용하면 매우 문제가 될 것입니다. – innaM

+0

호출 프로그램이이 정규식이나 다른 정규식에서 병목 현상을 일으키지 않으면 실제로 문제가되지 않습니다. 최적화 클럽의 첫 번째 규칙 : 최적화하지 않습니다. 최적화 클럽의 두 번째 규칙 : 측정하지 않고 최적화하지 마십시오. –

1

$&을 사용하면 성능에 미치는 영향을 쉽게 알 수 있습니다. 먼저 두 개의 벤치 마크 스크립트를 만들어야합니다. 의 이러한 벤치 마크를 실행하자,

### benchmark with $MATCH 

timethese -1, { 
    match_var => sub { 
     $str =~ /commodo/; 
     print $output $&; 
     $str =~ /^Lorem|ipsum/ and print $output 'yes'; 
    } 
} 

두 번째 벤치 마크 파일에 대한

이 지금

timethese -1, { 
    capture => sub { 
     $str =~ /(commodo)/; 
     print $output $1; 
     $str =~ /^Lorem|ipsum/ and print $output 'yes'; 
    } 
} 

을 사용하여 추가

#!/usr/bin/perl 

use strict; 
use warnings; 
use autodie; 
use File::Spec::Functions qw(devnull); 

open my $output, '>', devnull; 

my $str = <<EO_LIPSUM; 
Lorem ipsum dolor sit amet, consectetur adipisicing elit, 
sed do eiusmod tempor incididunt ut labore et dolore magna 
aliqua. Ut enim ad minim veniam, quis nostrud exercitation 
ullamco laboris nisi ut aliquip ex ea commodo consequat. 
Duis aute irure dolor in reprehenderit in voluptate velit 
esse cillum dolore eu fugiat nulla pariatur. Excepteur sint 
occaecat cupidatat non proident, sunt in culpa qui officia 
deserunt mollit anim id est laborum. 
EO_LIPSUM 

use Benchmark qw(timethese); 

최초의 벤치 마크를 들면 : 그들은 공통의 코드의 대부분을해야합니다 (은 각각이어야 함) :

 
Benchmark: running capture for at least 1 CPU seconds... 
    capture: 1 wallclock secs (1.05 usr + 0.00 sys = 1.05 CPU) @ 301485.20/s 
(n=315655) 
 
Benchmark: running match_var for at least 1 CPU seconds... 
match_var: 1 wallclock secs (1.22 usr + 0.02 sys = 1.23 CPU) @ 255591.09/s 
(n=315655) 

즉, $&을 사용하면이 경우 약 15 %의 속도 저하가 발생합니다. 둔화는 $&의 영향으로 인해 단순 정규 표현식 일치에 기인합니다.

$str =~ /^Lorem|ipsum/ and print $output 'yes'; 

라인의 경우 $& 버전은 실제로 더 빠르게 수행됩니다.

관련 문제