改行の $scaler の最後の文字をチェックするために、次のことを考え出しました。
if( $buffer !~ /\n$/ ) {
if( substr( $buffer, -1, 1 ) !~ /\n/ ) {
if( substr( $buffer, -1, 1 ) ne '\n' ) {
私ができるより速い方法はありますか?$buffer スカラーのサイズは大きくなる可能性があり、サイズが大きくなるほど、これらの条件の実行に時間がかかることに気付きました。$buffer の長さを含む別のスカラーがあります。
ありがとう
完全なコード:
#!/usr/bin/perl
use strict;
use warnings;
use Fcntl qw();
use Time::HiRes qw( gettimeofday tv_interval );
use constant BUFSIZE => 2 ** 21; # 2MB worked best for me, YMMV.
die "ERROR: Missing filename" if( !$ARGV[0] );
my $top = [gettimeofday];
sysopen( my $fh, $ARGV[0], Fcntl::O_RDONLY | Fcntl::O_BINARY ) or
die "ERROR: Unable to open $ARGV[0], because $!\n";
open my $output, ">", "/dev/null"; # for 'dummy' processing
my $size = -s $ARGV[0];
my $osiz = $size;
my( $buffer, $offset, $lnCtr ) = ( "", "", 0 );
while( $size ) {
my $read = sysread( $fh, $buffer, BUFSIZE, length($offset) );
$size -= $read;
my @lines = split /\n/, $buffer;
if( substr( $buffer, -1, 1 ) ne "\n" ) {
$offset = pop( @lines );
} else {
$offset = "";
}
for my $line ( @lines ) {
processLine( \$line );
$lnCtr++;
}
$buffer = $offset if( $offset );
}
close $fh;
print "Processed $lnCtr lines ($osiz bytes) in file: $ARGV[0] in ".
tv_interval( $top ).
" secs.\n";
print "Using a buffered read of ".BUFSIZE." bytes. - JLB\n";
sub processLine {
if( ref($_[0]) ) {
print $output ${$_[0]}."\n";
} else {
print $output $_[0]."\n";
}
return 0;
}
これをより速く実行しようとする試みで、その「収益が減少するポイント」に到達したと思います。私のRAID5 SSDがデータをフェッチできるのと同じくらい速くデータを読み込むことができるようになりました。ご覧のとおり、chomp() を使用しなかったのには理由があります。入力には何十万もの改行が含まれる可能性があり、処理のために行を分割できるようにするために、改行を保持する必要があります。
./fastread.pl newdata.log ファイル内の 516670 行 (106642635 バイト) を処理: newdata.log 0.674738 秒。2097152 バイトのバッファリングされた読み取りを使用します。- JLB