我有一个代码,用于比较两个文件之间某些特定术语的值。代码的主要耗时部分如下:
my @ENTIRE_FILE;
my %NETS;
my %COORDINATES;
my $INT=1;
my %IR_VALUES;
################################# READING
foreach my $IR_REPORT_FILE_1(@IR_REPORT_FILES){
{
open (FHIN, "<", $IR_REPORT_FILE_1) or die("Could not open $! for reading\n");
# chomp(my @ENTIRE_FILE = <FHIN>); # READS THE ENTIRE FILE
local undef $/;
@ENTIRE_FILE = split(/\n(.*NET.*)/,<FHIN>);
close (FHIN);
}
############################### BUILDING HASH
for my $i(1..$#ENTIRE_FILE/2){
if($ENTIRE_FILE[$i*2-1]=~ /^----.*\s+"(\w+)"\s+/){
my $net =$1;
my @ir_values_of_net = split(/\n/,$ENTIRE_FILE[$i*2]);
for my $val (@ir_values_of_net){
push ( @{ $NETS{$INT}{$net} }, $val ) if ($val =~ /^r.*\s+m1|v1_viadg|v1_viabar|m2|ay_viabar|ay_viadg|c1\s+/); # NETS{1}{VDD}=array of values, NETS{1}{VSS}, NETS{1}{AVDD}
}
}
}
$INT++; # For the next file: NETS{2}{VDD}, NETS{2}{VSS}, NETS{2}{AVDD}
}
############################### COMPARISON
my $loop_count=0;
foreach my $net(keys %{ $NETS{1} }){
print "net is $net\n";
foreach my $file_1_net( @{ $NETS{1}{$net} }){
my @sub_str_1 = split (' ', $file_1_net);
foreach my $file_2_net ( @{ $NETS{2}{$net} } ){
$loop_count++;
# my @sub_str_1 = split (' ', $file_1_net);
my @sub_str_2 = split (' ', $file_2_net);
if(($sub_str_1[2] eq $sub_str_2[2])&&(($sub_str_1[3].$sub_str_1[4].$sub_str_1[5].$sub_str_1[6] eq $sub_str_2[3].$sub_str_2[4].$sub_str_2[5].$sub_str_2[6]) || ($sub_str_1[3].$sub_str_1[4].$sub_str_1[5].$sub_str_1[6] eq $sub_str_2[5].$sub_str_2[6].$sub_str_2[3].$sub_str_2[4]))){
push (@{ $COORDINATES{$net}{X} },$sub_str_1[3],$sub_str_1[5]) if ($sub_str_1[3] && $sub_str_1[5]);
push (@{ $COORDINATES{$net}{Y} },$sub_str_1[4],$sub_str_1[6]) if ($sub_str_1[4] && $sub_str_1[6]);
my $difference=$sub_str_1[1]-$sub_str_2[1];
if($sub_str_1[3]=~/^-/){
push (@{ $MATCHED_RESISTORS{$net}{$sub_str_1[2].$sub_str_1[3].$sub_str_1[4].$sub_str_1[5].$sub_str_1[6]} }, $file_1_net,$file_2_net,$difference);
}else{
push (@{ $MATCHED_RESISTORS{$net}{$sub_str_1[2]."-".$sub_str_1[3].$sub_str_1[4].$sub_str_1[5].$sub_str_1[6]} }, $file_1_net,$file_2_net,$difference);
}
push (@{ $IR_VALUES{$net} }, $sub_str_2[1]);
last;
}
}
}
print max @{ $IR_VALUES{$net} };
print "\nloop count is $loop_count\n";
$loop_count = 0;
# <>;
}
我在代码上运行了一个分析器。以下是代码上面部分的输出:
一些统计数据:
element_1: 14 element_1: 316 element_1: 8
我的问题很简单:如何让我的代码运行得更快?
示例数据文件_1:
r6_2389 1.29029e-05 ay_viabar 23.076 57.755 22.628 57.755 4.5 0 0 3.68449e-06 -5.99170336965613
r6_2397 1.29029e-05 ay_viabar 22.948 57.755 22.628 57.755 4.5 0 0 3.68449e-06 -5.99170336965613
r6_2400 1.29029e-05 ay_viabar 22.82 57.755 22.628 57.755 4.5 0 0 3.68449e-06 -5.99170336965613
r6_2403 1.29029e-05 ay_viabar 22.692 57.755 22.628 57.755 4.5 0 0 3.68449e-06 -5.99170336965613
r6_971 1.3279e-05 c1 9.492 45.742 -0.011 46.779 0.001 9.5589 10 0.0508653
示例数据文件_2:
r6_9261 0.00206167 ay_viabar 23.076 57.755 22.628 57.755 4.5 0 0 0.0207546
r6_9258 0.00206167 ay_viabar 22.948 57.755 22.628 57.755 4.5 0 0 0.0161057
r6_9399 0.00206167 ay_viabar 22.82 57.755 22.628 57.755 4.5 0 0 0.0127128
r6_9486 0.00206167 ay_viabar 22.692 57.755 22.628 57.755 4.5 0 0 0.0103186
r6_1061 1.3279e-05 cb_pc_viadg -6.696 44.157 -0.159 44.847 0.001 0 0 0
示例输出:
r6_9261 0.00206167 ay_viabar 23.076 57.755 22.628 57.755 4.5 0 0 0.0207546
r6_9258 0.00206167 ay_viabar 22.948 57.755 22.628 57.755 4.5 0 0 0.0161057
r6_9399 0.00206167 ay_viabar 22.82 57.755 22.628 57.755 4.5 0 0 0.0127128
r6_9486 0.00206167 ay_viabar 22.692 57.755 22.628 57.755 4.5 0 0 0.0103186
示例输出基本上被推入另一个进一步处理的哈希。但是根据分析器,构建此哈希消耗的总运行时间约占总运行时间的90%。
答案 0 :(得分:2)
好的,所以我的第一个想法是 - 你有一个3深的循环,这将永远是低效的。我们可能会以很快的速度交换内存。
假设“更大”&#39;文件是&#39; sample_1&#39;,否则交换它们。
在此示例中 - sample_2
将消耗与行数成比例的内存 - 因此我们理想地希望它是较小的文件。您可能需要交换匹配/测试,具体取决于file1 cols 5,6,3,4是否与file2匹配,反之亦然。
但希望这说明一个有用的概念来解决你的问题,如果不是完全解决它?
这样的事情可以解决问题:
#!/usr/bin/env perl
use strict;
use warnings;
my %is_match;
open ( my $sample_1, '<', 'sample1.txt' ) or die $!;
open ( my $sample_2, '<', 'sample2.txt' ) or die $!;
# first of all, column 2 , 3,4,5,6 should match between 2 files.
# and then print out both matching lines from two files.
# column 3,4,5,6 from one file can match with column 5,6,3,4.
while ( <$sample_2> ) {
my @row = split;
#insert into hash
#this would be much clearer if the fields were named rather than numbered
#I think.
$is_match{$row[3]}{$row[4]}{$row[5]}{$row[6]}++;
$is_match{$row[5]}{$row[6]}{$row[3]}{$row[4]}++;
}
while ( <$sample_1> ) {
my @row = split;
#print the current line if it matches from the hash above.
print if $is_match{$row[3]}{$row[4]}{$row[5]}{$row[6]};
}
因为这会迭代每个文件一次,所以它应该快得多。并且因为你的一个文件很小,那么你应该先读入一个文件到内存中。
使用提供的样本数据,可以获得所需的输出。
第一个循环读取文件,选择您感兴趣的字段并根据您的4个键将它们插入到散列中。
然后它再次为另一组有效匹配键执行此操作。
第二个循环读取另一个文件,选择密钥并检查散列中是否存在任何组合。并打印出当前行。