我的perl模块需要使用一个大约309,000行的查找表。
目前,将表加载到数组中的部分(粗略地)看起来像这样:
use strict;
use warnings;
# load all the data from below
my @ref_data;
while (<DATA>) {
push @ref_data, $_
}
close DATA;
__DATA__
00004f15ed000023f2
00005015fc000623ec
000051160a000b23e7
000052161d001523e2
0000531631002223de
0000541645002e23da
... etc ...
我自己的实验表明,此while
循环加载数据大约需要0.1秒。这大约是这样做的两倍:
use strict;
use warnings;
# load all the data from below
my @ref_data = <DATA>;
close DATA;
__DATA__
00004f15ed000023f2
00005015fc000623ec
000051160a000b23e7
000052161d001523e2
0000531631002223de
0000541645002e23da
... etc ...
这两者都比仅仅qw(...)
围绕所有数据行或编辑源以便一次加载一个项目快得多。
我可以猜测大约100毫秒的大部分时间是磁盘时间,但是while
循环是初始化我的数组的最快方法,还是我们可以通过使用其他一些Perl构造来加快速度?
答案 0 :(得分:3)
我针对三种方法做了一些基准测试。我使用外部文件进行阅读(而不是__DATA__
)。该文件包含300万行您使用的确切数据。
这些方法正在啜饮文件,逐行读取文件,并使用Storable
作为上面提到的Sobrique。每项任务都运行100次。以下是结果,显示一旦使用Storable
存储,它比其他两个快得多(比直线快118%,比啜食快45%):
Rate by_line by_slurp by_store
by_line 1.08/s -- -33% -54%
by_slurp 1.62/s 50% -- -31%
by_store 2.36/s 118% 45% --
这是我使用的代码:
#!/usr/bin/perl
use warnings;
use strict;
use Benchmark qw(cmpthese timethese);
use Storable;
my $file = 'in.txt';
storeit();
cmpthese(100, {
'by_line' => \&by_line,
'by_slurp' => \&by_slurp,
'by_store' => \&by_store,
});
sub by_line {
open my $fh, '<', $file
or die "Can't open $file: $!";
my @ref_data;
for my $line (<$fh>){
push @ref_data, $line;
}
}
sub by_slurp {
open my $fh, '<', $file
or die "Can't open $file: $!";
my @ref_data = <$fh>;
}
sub storeit {
open my $fh, '<', $file
or die "Can't open $file: $!";
my @ref_data = <$fh>;
close $fh;
store \@ref_data, 'store.dat';
}
sub by_store{
my @ref_data = retrieve('store.dat');
}
答案 1 :(得分:2)
DATA
是一个嵌入到脚本中的特殊文件句柄。它与正常读取文件中的数据没有太大区别。我建议虽然使用300k线的内联数据可能不是接近它的理想方式。
你看过Storable
了吗?您可能会发现可以store
和retrieve
数据结构 - 您可能需要保留文件以进行初始加载。
或者 - 您实际上是否需要在内存中保存所有参考数据?直接内存访问速度很快,但如果你不进行顺序密钥处理,你可能会发现按需查找数据库样式更好吗?
如果失败了 - 您可能还会发现拥有一个独立的“加载器”线程来异步处理您的文件也可能是一个选项,因为虽然它仍然需要时间加载到内存中,但您的程序可以继续进行数据处理正在加载。
但从根本上说 - 你正在从磁盘中连续读取大量数据。它总是受到磁盘速度的限制。更快的磁盘意味着更快的负载。解决方法是从磁盘移动到内存(如数据库)。