0

我是编程的初学者,而不仅仅是 perl!请让我知道需要更改的内容或其他方法。

需要优化 perl 代码才能运行得更快。对于一个包含 300 万行的大约 500MB 文件的测试运行,运行时间为 28 分钟。

我知道一个工具可以在 15 分钟内处理 3900 万行,但我想在命令提示符下运行它而不使用该工具。

早些时候我使用了 Date::Manip 和 Date::Parse 并继续使用 DateTime,认为它应该更快。

我的方法是如果日期是 ISO-8601(即 YYYY-MM-DD)并且我们不需要验证它们,我们可以按字典顺序进行比较(即 lt 和 gt 运算符。)

  • 输入文件日期格式为 07/18/2013 13:45:49
  • 输入文件大小 42GB。
  • 行数 3900 万。
  • 列分隔符:|~|
  • 平台:GNU/Linux

我尝试了“>”和“gt”,但在运行时没有发现任何差异。

Code snippet:

use DateTime::Format::Strptime;

my $idate = "07/17/2013 00:00:00";

my $Strp = DateTime::Format::Strptime->new(
                   pattern     => '%m/%d/%Y %H:%M:%S',
                  );

my $inputdt = $Strp->parse_datetime($idate);

open (FILE,"myinputfile.dat") or die "could not input File\n";
while (defined(my $line = <FILE>)) {
    my @chunks = split '[|]~[|]', $line;
    my $fdate = $Strp->parse_datetime($chunks[6]);
    if ( $fdate > $inputdt) {
    open(FILEOUT, ">>myoutputfile.dat") or die "Could not write\n";
    print FILEOUT "$line";
                         }
}
close(FILE);
close (FILEOUT);
4

1 回答 1

2

这里有两个半大的性能问题:

  1. 您在每次迭代中打开输出文件。只需在循环之前打开一次。
  2. parse_datetime返回一个 DateTime 对象。Perl 面向对象意味着大量开销。因为您的模式定义明确,我们可以自己进行解析,并删除所有面向对象。
  3. 读取 GB 范围内的文件只需要一些时间。要加快速度,请升级您的硬件(例如升级到 SSD)。

要将日期字符串解析为可排序的表示,我们只需将各个部分重新排序为字符串:

# %m/%d/%Y %H:%M:%S → %Y/%m/%d %H:%M:%S
$fdate =~ s{^ ([0-9]{2} / [0-9]{2}) / ([0-9]{4}) }{$2/$1}x;

if ($fdate gt $inputdate) { ... }

这将导致代码

use strict; use warnings;

use constant DATE_FIELD => shift @ARGV;

my $inputdate = shift @ARGV;
$inputdate =~ s{^ ([0-9]{2} / [0-9]{2}) / ([0-9]{4}) }{$2/$1}x;

<>; # remove the header line

while (<>) {
    my $filedate = (split /\|~\|/, $_, DATE_FIELD + 2)[DATE_FIELD];
    $filedate =~ s{^ ([0-9]{2} / [0-9]{2}) / ([0-9]{4}) }{$2/$1}x;
    print if $filedate gt $inputdate;
}

在命令行上指定输入和输出以及开始日期,例如

./script 6 '07/17/2013 00:00:00' myinputfile.dat >>myoutputfile.dat
于 2013-07-18T13:39:09.750 回答