我制作了以下Perl脚本来处理工作中的某些文件操作,但是它在运行时运行得太慢而无法投入生产。
我不太了解Perl(不是我的一种语言),所以有人可以帮我识别和替换这个脚本的部分内容,因为它处理了大约4000万行吗? / p>
传输的数据格式为:
col1|^|col2|^|col3|!|
col1|^|col2|^|col3|!|
... 40 million of these.
在脚本的这一部分之前计算date_cols数组,并且基本上保存包含预转换格式的日期的列的索引。
这是将为每个输入行执行的脚本部分。我已将其清理干净并添加了评论,但如果需要其他任何内容,请告知我们:
## Read from STDIN until no more lines are arailable.
while (<STDIN>)
{
## Split by field delimiter
my @fields = split('\|\^\|', $_, -1);
## Remove the terminating delimiter from the final field so it doesn't
## interfere with date processing.
$fields[-1] = (split('\|!\|', $fields[-1], -1))[0];
## Cycle through all column numbres in date_cols and convert date
## to yyyymmdd
foreach $col (@date_cols)
{
if ($fields[$col] ne "")
{
$fields[$col] = formatTime($fields[$col]);
}
}
print(join('This is an unprintable ASCII control code', @fields), "\n");
}
## Format the input time to yyyymmdd from 'Dec 26 2012 12:00AM' like format.
sub formatTime($)
{
my $col = shift;
if (substr($col, 4, 1) eq " ") {
substr($col, 4, 1) = "0";
}
return substr($col, 7, 4).$months{substr($col, 0, 3)}.substr($col, 4, 2);
}
答案 0 :(得分:3)
如果纯粹为了提高效率而写,我会写下这样的代码:
sub run_loop {
local $/ = "|!|\n"; # set the record input terminator
# to the record seperator of our problem space
while (<STDIN>) {
# remove the seperator
chomp;
# Split by field delimiter
my @fields = split m/\|\^\|/, $_, -1;
# Cycle through all column numbres in date_cols and convert date
# to yyyymmdd
foreach $col (@date_cols) {
if ($fields[$col] ne "") {
# $fields[$col] = formatTime($fields[$col]);
my $temp = $fields[$col];
if (substr($temp, 4, 1) eq " ") {
substr($temp, 4, 1) = "0";
}
$fields[$col] = substr($temp, 7, 4).$months{substr($temp, 0, 3)}.substr($temp, 4, 2);
}
}
print join("\022", @fields) . "\n";
}
}
优化是:
chomp
删除末尾的|!|\n
字符串formatTime
子。
Perl中的子程序调用非常昂贵。如果必须非常有效地使用subs,则可以使用
&subroutine(@args)
语法禁用原型检查。如果省略@args
,则当前参数@_
对被调用的子可见。这可能会导致错误或其他性能。明智地使用。也可以使用goto &subroutine;
语法,但这会干扰return
(基本上是尾调用)。不要使用。
%months
,因为散列很昂贵。
答案 1 :(得分:2)
您必须对您的数据集进行基准测试以进行比较,但您可以使用正则表达式。 (你的正则表达不友好的字段和记录分隔符使情况变得更糟!)
my $i = 0;
our %months = map { $_ => sprintf('%02d', ++$i) } qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
while (<DATA>) {
s! \|\^\| !\022!xg; # convert field separator
s/ \| !\| $ //xg; # strip record terminator
s/\b(\w{3}) ( \d|\d\d) (\d{4}) \d\d:\d\d[AP]M\b/${3} . $months{$1} . sprintf('%02d', $2) /eg;
print;
}
如果其中一个非@date_cols
字段与日期正则表达式匹配,则无法执行您想要的操作。
答案 2 :(得分:0)
在我的工作中,有时我需要从350多个前端grep错误日志等。我使用脚本模板调用&#34; SMP grep&#34; ;)简单:
stat
文件,获取文件长度read()
,找到&#34; \ n&#34;并计算抵消额。fork()
创建num_processor工作者,每个工作在自己的块上如果你在grep或其他CPU操作中使用正则表达式,这可能会有所帮助(我认为)。管理员抱怨这个脚本会占用磁盘吞吐量,但如果服务器有8个CPU,那么这是唯一的瓶颈=)另外,显然如果你需要解析1周数据,你可以在服务器之间进行划分。
明天如果有兴趣我可以发布代码。