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!

questionAnswers(4)

yourAnswerToTheQuestion