Najszybszy parser CSV w Perlu
Tworzę podprogram, który:
(1) Analizuje plik CSV;
(2) I sprawdza, czy wszystkie wiersze w tym pliku mają oczekiwaną liczbę kolumn. Szumie, jeśli liczba kolumn jest nieprawidłowa.
Gdy liczba wierszy wynosi od tysięcy do milionów,jak myślisz, co to jestnajbardziej wydajny sposób to zrobić?
W tej chwili wypróbowuję te implementacje.
(1) Podstawowy parser plików
open my $in_fh, '<', $file or
croak "Cannot open '$file': $OS_ERROR";
my $row_no = 0;
while ( my $row = <$in_fh> ) {
my @values = split (q{,}, $row);
++$row_no;
if ( scalar @values < $min_cols_no ) {
croak "Invalid file format. File '$file' does not have '$min_cols_no' columns in line '$row_no'.";
}
}
close $in_fh
or croak "Cannot close '$file': $OS_ERROR";
(2) Używanie Text :: CSV_XS (bind_columns i csv-> getline)
my $csv = Text::CSV_XS->new () or
croak "Cannot use CSV: " . Text::CSV_XS->error_diag();
open my $in_fh, '<', $file or
croak "Cannot open '$file': $OS_ERROR";
my $row_no = 1;
my @cols = @{$csv->getline($in_fh)};
my $row = {};
$csv->bind_columns (\@{$row}{@cols});
while ($csv->getline ($in_fh)) {
++$row_no;
if ( scalar keys %$row < $min_cols_no ) {
croak "Invalid file format. File '$file' does not have '$min_cols_no' columns in line '$row_no'.";
}
}
$csv->eof or $csv->error_diag();
close $in_fh or
croak "Cannot close '$file': $OS_ERROR";
(3) Używanie Text :: CSV_XS (csv-> parse)
my $csv = Text::CSV_XS->new() or
croak "Cannot use CSV: " . Text::CSV_XS->error_diag();
open my $in_fh, '<', $file or
croak "Cannot open '$file': $OS_ERROR";
my $row_no = 0;
while ( <$in_fh> ) {
$csv->parse($_);
++$row_no;
if ( scalar $csv->fields < $min_cols_no ) {
croak "Invalid file format. File '$file' does not have '$min_cols_no' columns in line '$row_no'.";
}
}
$csv->eof or $csv->error_diag();
close $in_fh or
croak "Cannot close '$file': $OS_ERROR";
(4) Korzystanie z Parse :: CSV
use Parse::CSV;
my $simple = Parse::CSV->new(
file => $file
);
my $row_no = 0;
while ( my $array_ref = $simple->fetch ) {
++$row_no;
if ( scalar @$array_ref < $min_cols_no ) {
croak "Invalid file format. File '$file' does not have '$min_cols_no' columns in line '$row_no'.";
}
}
Testowałem je za pomocą modułu Benchmark.
use Benchmark qw(timeit timestr timediff :hireswallclock);
A to są teliczby (w sekundach) że mam:
1000 wierszy pliku:
Implementacja 1: 0,0016
Implementacja 2: 0,0025
Wdrożenie 3: 0,0050
Implementacja 4: 0,0097
10 000 wierszy pliku:
Implementacja 1: 0,0204
Implementacja 2: 0,0244
Wdrożenie 3: 0,0523
Wdrożenie 4: 0,1050
1,500,000 wierszy pliku:
Implementacja 1: 1.8697
Implementacja 2: 3.1913
Wdrożenie 3: 7.8475
Implementacja 4: 15.6274
Biorąc pod uwagę te liczby, wyciągnę wniosek, że prosty parser jest najszybszy, ale z tego, co przeczytałem z różnych źródeł, Text :: CSV_XS powinien być najszybszy.
Czy ktoś mnie oświeci na ten temat? Czy jest coś nie tak z tym, jak korzystałem z modułów? Bardzo dziękuję za Twoją pomoc!