이 답변을 통해 스크립트를 왜 프로파일로 작성하여 느린 이유와 장소를 알 수 있습니다. CPAN에서 설치해야하는 Perl 프로파일 러 Devel::NYTProf을 사용합니다.
직접 해보기 전에 저자에 대해 프로파일 링에 대해 this talk을 보시기 바랍니다. 이것은 드문 경우에만 수행되어야한다는 것을 아는 것이 중요합니다. 당신은 그런 경우입니다.
첫째, the JSON API of baconipsum.com를 사용하여 다음 명령을 사용하여 테스트 입력을 만들 :이 파일은 70메가바이트에 대해하고 1 개 백만 행이됩니다
$ curl -s \
'https://baconipsum.com/api/?type=meat-and-filler&format=text&sentences=100' \
| perl -nE 'for $i (1 .. 10_000) { say for map lc, split /\./}' >log.txt
. 시험하기에 충분합니다.
$ ls -lah
-rw-rw-r-- 1 simbabque simbabque 69M Nov 28 13:36 log.txt
$ tail log.txt
Nisi magna pig pastrami, in chicken elit meatball
Consequat laborum rump kevin beef ham hock proident tempor ex strip steak
Shankle kielbasa in nulla
Consectetur picanha pork belly, drumstick tail tempor alcatra pariatur eiusmod
Tongue tail meatloaf cupim ut do sed, cillum kevin id ex dolore t-bone
Ut cow nulla brisket ball tip ipsum ham strip steak culpa cillum
Doner chicken sint duis in, andouille labore eiusmod
Bacon tempor nostrud, short loin occaecat cow nulla ipsum strip steak pastrami corned beef turducken
Ball tip labore chicken pancetta cupim
Ham leberkas pastrami, exercitation id porchetta tri-tip beef voluptate shoulder ipsum meatloaf sunt ea.
다음으로 스크립트를 준비합니다. 필자는보다 현대적인 Perl을 만들기 위해 몇 가지 변경을했습니다.이 세 인수 인 open
과 어휘 파일 핸들과 같습니다.
$ cat patterns.pl
use strict;
use warnings;
use Data::Dumper;
my $InListOfPatterns = '[email protected]@@[email protected]@@steak';
my $InStartLineNumber = 2;
my @pat_array = split('@@@', $InListOfPatterns);
my $num_pat = @pat_array;
my @match_count;
for (my $i = 0; $i < $num_pat; $i = $i + 1) {
$match_count[$i] = 0;
}
open my $fh,'<','log.txt' or die "can not open file :$!";
while (<$fh>) {
chomp;
if ($. > $InStartLineNumber) {
for (my $j = 0; $j < $num_pat; $j = $j + 1) {
if ($_ =~ m/\Q$pat_array[$j]\E/) {
$match_count[$j] = ($match_count[$j] + 1);
}
}
}
}
print Dumper \@match_count;
내 컴퓨터에서 6 초 정도 걸리며 끝에있는 각 패턴의 일치 개수를 인쇄합니다.
이제 이것을 Devel::NYTProf으로 어떻게 프로파일 할 수 있는지 살펴 보겠습니다. 이 명령을 실행하면됩니다. -d
플래그는 Perl이 디버거 인터페이스를 사용하도록 지시하고 :NYTProf
은 Devel::NYTProf
디버거를 사용합니다.
$ perl -d:NYTProf patterns.pl
$VAR1 = [
20000,
300000,
90000
];
디렉토리에 nytprof.out
이라는 파일이 있습니다.
$ nytprofhtml --no-flame --open
Reading nytprof.out
Processing nytprof.out data
Writing line reports to nytprof directory
100% ...
이 브라우저 창 또는 기존 브라우저에서 새 탭을 열고 당신에게이 같은 표시됩니다 :
우리는 의 라인 보고서에 가고 싶다을 patterns.pl. 빨간 선은 NYTProf가 매우 느린 것으로 간주됩니다.
라인 17에서 가장 명백한 것은 chomp
입니다.이 라인은 폐기 된 라인에서도 호출됩니다. 물론이 예제에서는 한 줄만 건너 뛰었지만, 그럴 수도 있습니다. if
뒤에 chomp
을 입력하십시오.
우리는 또한 가장 중요한 시간이 if
에 소요되는 것을 볼 수 있습니다. chorboa says in his answer on your cross-posted Perlmonks question으로 명명 된 캡처 그룹과 함께 단일 패턴을 사용할 수 있습니다. 저는 이것을 두 단계로 시연 해 보았습니다. 그래서 그가 왜 그가 한 일을하는지 봅니다.
use strict;
use warnings;
use Data::Dumper;
my $InListOfPatterns = '[email protected]@@[email protected]@@steak';
my $InStartLineNumber = 2;
my @pat_array = split('@@@', $InListOfPatterns);
open my $fh, '<', 'log.txt' or die "can not open file :$!";
my %matched;
while (<$fh>) {
if ($. > $InStartLineNumber) {
chomp;
# these two are inside the loop, which is bad
my $i;
my $regex = join '|', map +($i++, "(?<m$i>$_)")[1], map quotemeta, @pat_array;
$matched{ (grep defined $-{$_}[0], keys %-)[0] }++ if /$regex/;
}
}
print Dumper \%matched;
프로파일 러를 다시 실행하고 결과를 확인하십시오. 루프 내부에서보다 복잡한 작업을 수행하기 때문에 시간이 오래 걸립니다. 그 나쁜.
그것은 거의 1 백만 라인의 하나 하나에 대해 새롭게 동일한 패턴을 컴파일, 라인 (18)에 그 루프 내에서 거의 2 초 보냈다.
그래서 루프에서 벗어나기를 바랄 것입니다. 예를 들어, choroba가 자신의 게시물에있는 것처럼 말입니다.
use strict;
use warnings;
use Data::Dumper;
my $InListOfPatterns = '[email protected]@@[email protected]@@steak';
my $InStartLineNumber = 2;
my @pat_array = split('@@@', $InListOfPatterns);
my $i;
my $regex = join '|', map +($i++, "(?<m$i>$_)")[1], map quotemeta, @pat_array;
open my $fh, '<', 'log.txt' or die "can not open file :$!";
my %matched;
while (<$fh>) {
if ($. > $InStartLineNumber) {
chomp;
$matched{ (grep defined $-{$_}[0], keys %-)[0] }++ if /$regex/;
}
}
print Dumper \%matched;
프로파일 러를 통해이를 다시 실행하면이를보고합니다.
패턴 생성의 호출은 이제 한 번만 호출됩니다. 그것은 훨씬 더 빠릅니다.
불행히도 전반적인 승리는 적어도이 파일 크기에서는 그리 높지 않습니다. 원래 코드의 for
루프에 대해 12.4 초 + 1.1 초가 걸렸으며 이제는 12.2 초가되었습니다. 1.3 초는 단지 100 만 행으로는별로 중요하지 않습니다. 그러나 파일의 행이 더 많을 수 있으며 특히 더 많은 패턴을 추가하는 경우 파일이 전체적으로 약간 더 빨라집니다.
패턴을 5 개로 늘리면 새 구현에서는 23.6 초, 원래 구현에서는 1.78 초 + 23.6 초가됩니다. 그것은 1.78s의 차이입니다.
3 개 대신 루프에서 하나의 일치 항목을 얻는 이점은 매우 명확하지만 어떤 패턴이 일치했는지 파악하는 캡처 그룹은 가격이 높으며 매번 생성되는 조회 해시가있는 명명 된 캡처 그룹은 훨씬 비쌉니다 .
대신이 값을 솔루션 in Sobrique's answer과 비교하면 3.78s이고 원래 1.78s + 23.6s입니다. 이 차이는 이제 거의 한 자리수로 매우 중요합니다. 순서 번호를 사용하여 패턴을 얻으려면 루프 외부에 하나 또는 두 줄의 추가 코드를 작성해야합니다. 이는 무시할 수 있습니다.
모든 측정 값은 기계마다 크게 다르며 동시에 실행되는 다른 프로세스의 영향을받습니다. 귀하의 컴퓨터에서 그들은 완전히 다를 수 있습니다. 벤치마킹은 어렵고 종종 정확하지 않습니다.
귀하의 질문은 [codereview.se]에 더 잘 맞을 것입니다. 이미 작업 코드가 있으며이를 개선하려고합니다. 어쨌든, [edit] 테스트 할 두 줄의 로그 라인을 포함시키고 패턴 목록을 보여주십시오. 해당 정보를 공개하고 싶지 않은 경우 동일한 문제를 보여주는 예제 데이터가 포함 된 새로운 전체 프로그램을 작성하고 포함하십시오. 이를 [mcve]라고합니다. – simbabque
_ 새로운 코드/아이디어로 나를 도울 때 ._ "언제"는 – ssr1012
xpost가/대답으로 http://www.perlmonks.org/?node_id=1204414 – toolic