我测试的哈希包含大约70000所大学,每所大学包含大约20名学生。 我尝试了5次,结果如下。 foreach性能和(每个)性能有很大差异。为什么会这样?
带循环的代码:
while ( my ($college_code, $college_info_hr) = each (%{$college_data_hr}) ) {
while ( my ($student_num, $student_info_hr) = each (%{$college_info_hr->{'students'}}) ) {
if($student_num < 104000) { ## Delete the info of students before 2004.
delete $college_info_hr->{'students'}{$student_num};
}
}
}
使用foreach循环的代码:
foreach my $college_code (keys %{$college_data_hr}) {
foreach my $student_num (keys %{$college_data_hr->{$college_code}{'students'}}) {
if($student_num < 104000) { ## Delete the info of students before 2004.
delete $college_data_hr->{$college_code}{'students'}{$student_num};
}
}
}
当大学数量为70,000时,执行时间为:
对于带while循环的代码(间隔时间以秒为单位):
间隔时间:2.186621
间隔时间:2.058644
间隔时间:2.055645
间隔时间:2.101637
间隔时间:2.124632
对于带有foreach循环的代码:(间隔时间以秒为单位)
间隔时间:1.341768
间隔时间:1.436751
间隔时间:1.346529
间隔时间:1.302775
间隔时间:1.356765
当大学数量为248,000时,执行时间为:
(while循环的执行时间)
间隔时间:9.084427
间隔时间:8.438684
间隔时间:9.329338
间隔时间:9.169687
(foreach循环的执行时间)
间隔时间:5.502048
间隔时间:6.386692
间隔时间:5.596032
间隔时间:5.620144
答案 0 :(得分:7)
foreach
版本仅在每个大学时取消引用$college_data_hr->{$college_code}{'students'}
hashref,因此比每个学生需要执行一次的while
版本更快。
foreach
版本可能会使用更多内存,因为它需要构建包含每个哈希键的临时列表。
Data::Alias可能会帮助您加快while
解决方案的速度。我没有对此进行基准测试,但它应该相当快......
use Data::Alias;
while ( my ($college_code, $college_info_hr) = each %$college_data_hr ) {
alias ( my %students = %{$college_info_hr->{'students'}} );
while ( my ($student_num, $student_info_hr) = each %students ) {
if ($student_num < 104000) { ## Delete the info of students before 2004.
delete $students{$student_num};
}
}
}
答案 1 :(得分:2)
每次通过while
循环都需要执行大量操作(enter
和leave
以外的所有操作都适用于您的代码。)
>perl -MO=Concise,-exec -e"my ($college_code, $college_info_hr) = each (%{$college_data_hr})"
1 <0> enter
2 <;> nextstate(main 2 -e:1) v:{
3 <0> pushmark s
4 <#> gv[*college_data_hr] s
5 <1> rv2sv sKM/DREFHV,1
6 <1> rv2hv[t4] lKRM/1
7 <1> each lK/1
8 <0> pushmark sRM*/128
9 <0> padsv[$college_code:2,3] lRM*/LVINTRO
a <0> padsv[$college_info_hr:2,3] lRM*/LVINTRO
b <2> aassign[t5] vKS
c <@> leave[1 ref] vKP/REFC
-e syntax OK
将值复制到$college_code
,$college_info_hr
中。从好的方面来说,它们不是字符串。
你的foreach循环没有那个。每次传递都会发生的唯一事情是更改$college_code
别名的内容。很快。当然,缺点是会占用更多内存。
替代方案:
for my $college_code (keys %$college_data_hr) {
my $students = $college_data_hr->{$college_code}{students};
delete @$students{ grep $_ < 104000, keys %$students };
}