我这里有 2 个文件,它们是 newFile 和 LookupFile(它们是大文件)。将在 LookupFile 中搜索 newFile 中的内容并进行进一步处理。此脚本运行良好,但是执行需要更多时间。你能告诉我这里可以做些什么来提高性能吗?您能否让我知道我们是否可以将文件转换为哈希以提高性能?
我的文件如下所示
新建文件和查找文件:
acl sourceipaddress subnet destinationipaddress 子网端口号。.
脚本:
#!/usr/bin/perl
use strict;
use warnings;
use File::Slurp::Tiny 'read_file';
use File::Copy;
use Data::Dumper;
use File::Copy qw(copy);
my %options = (
LookupFile => {
type => "=s",
help => "File name",
variable => 'gitFile',
required => 1,
}, newFile => {
type => "=s",
help => "file containing the acl lines to checked for",
variable => ‘newFile’,
required => 1,
} );
$opts->addOptions(%options);
$opts->parse();
$opts->validate();
my $newFile = $opts->getOption('newFile');
my $LookupFile = $opts->getOption('LookupFile');
my @LookupFile = read_file ("$LookupFile");
my @newFile = read_file ("$newFile");
@LookupFile = split (/\n/,$LookupFile[0]);
@newLines = split (/\n/,$newFile[0]);
open FILE1, "$newFile" or die "Could not open file: $! \n";
while(my $line = <FILE1>)
{
chomp($line);
my @columns = split(' ',$line);
$var = @columns;
my $fld1;
my $cnt;
my $fld2;
my $fld3;
my $fld4;
my $fld5;
my $dIP;
my $sIP;
my $sHOST;
my $dHOST;
if(....)
if (....) further checks and processing
)
在任何优化之前要做的第一件事是分析您的代码。这将告诉您哪些线路占用的时间最多,以及它们被调用的频率,而不是猜测。Devel::NYTProf是一个很好的工具。
这是个问题。
my @LookupFile = read_file ("$LookupFile");
my @newFile = read_file ("$newFile");
@LookupFile = split (/\n/,$LookupFile[0]);
@newLines = split (/\n/,$newFile[0]);
read_file
将整个文件作为一个大字符串读取(应该是my $contents = read_file(...)
,使用数组很尴尬)。然后它将整个内容拆分为换行符,复制文件中的所有内容。这对内存来说非常缓慢和困难,而且没有必要。
相反,使用read_lines
. 这将在文件读取时将文件拆分为行,从而避免昂贵的副本。
my @lookups = read_lines($LookupFile);
my @new = read_lines($newFile);
下一个问题是$newFile
再次打开并逐行迭代。
open FILE1, "$newFile" or die "Could not open file: $! \n";
while(my $line = <FILE1>) {
这是一种浪费,因为您已经将该文件读入内存。使用其中之一。但是,一般来说,逐行处理文件比将它们全部放入内存要好。
以上将加快速度,但他们没有解决问题的关键。这可能是真正的问题......
将在 LookupFile 中搜索 newFile 中的内容并进行进一步处理。
你没有展示你在做什么,但我会想象它看起来像这样......
for my $line (@lines) {
for my $thing (@lookups) {
...
}
}
也就是说,对于一个文件中的每一行,您正在查看另一个文件中的每一行。这就是所谓的 O(n^2) 算法,这意味着当您将文件的大小加倍时,您的时间将增加四倍。
如果每个文件有 10 行,则内部循环将需要 100 (10^2) 圈。如果他们有 100 行,则需要 10,000 (100^2)。1,000 行将需要 1,000,000 次。
随着 O(n^2) 随着尺寸变大,事情变得非常缓慢。
您能否让我知道我们是否可以将文件转换为哈希以提高性能?
你的想法是对的。您可以将查找文件转换为哈希以加快速度。假设它们都是单词列表。
# input
foo
bar
biff
up
down
# lookup
foo
bar
baz
并且您想检查input
中的任何行是否与lookup
.
首先,您会读lookup
入并将其转换为哈希值。然后你会阅读input
并检查每一行是否在哈希中。
use strict;
use warnings;
use autodie;
use v5.10;
...
# Populate `%lookup`
my %lookup;
{
open my $fh, $lookupFile;
while(my $line = <$fh>) {
chomp $line;
$lookup{$line} = 1;
}
}
# Check if any lines are in %lookup
open my $fh, $inputFile;
while(my $line = <$fh>) {
chomp $line;
print $line if $lookup{$line};
}
这样您只需遍历每个文件一次。这是一个 O(n) 算法,意思是线性缩放,因为哈希查找基本上是瞬时的。如果每个文件有 10 行,那么每个循环只需要 10 次迭代。如果它们有 100 行,则每个循环只需要 100 次迭代。1000 行,1000 次迭代。
最后,您真正想做的是跳过所有这些并为您的数据创建一个数据库并进行搜索。SQLite是一个不需要服务器,只需要一个文件的 SQL 数据库。将您的数据放在那里并使用DBD::SQLite对其执行 SQL 查询。
虽然这意味着您必须学习 SQL,并且构建和维护数据库是有成本的,但这速度很快,最重要的是非常灵活。SQLite 可以快速进行各种搜索,而无需编写大量额外代码。SQL数据库是一个很常见的数据库,所以学习SQL是一个很好的投资。
由于您要拆分文件,my @columns = split(' ',$line);
因此它可能是一个包含许多字段的文件。这很可能会很好地映射到 SQL 表。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句