Performance Perl创建对象的速度非常慢

Performance Perl创建对象的速度非常慢,performance,perl,object,Performance,Perl,Object,我有一个perl脚本,它从数据库中读取约50000行,并将它们存储在哈希数组中。标准DBI代码。我宁愿将数据放入可以非常干净地传递给其他代码模块的对象中,而不是直接处理哈希。我从中读取的表中有15个以上的列。我的代码基本上如下所示: my $db = DBI->connect(); # Just pretend you see a proper DBI connect here my $resultSet = $db->selectall_arrayref($sql); $db-&g

我有一个perl脚本,它从数据库中读取约50000行,并将它们存储在哈希数组中。标准DBI代码。我宁愿将数据放入可以非常干净地传递给其他代码模块的对象中,而不是直接处理哈希。我从中读取的表中有15个以上的列。我的代码基本上如下所示:

my $db = DBI->connect(); # Just pretend you see a proper DBI connect here
my $resultSet = $db->selectall_arrayref($sql);
$db->disconnect();

# Here's where the problem starts.
my %objects;
for my $row (@{$resultSet}) {
    my ($col1, $col2, ..., $col15) = @{$row};
    my %inputHash;
    $inputHash{col1} = $col1 if $col1;
    ...
    $inputHash{col15} = $col1 if $col15;
    my $obj = Model::Object->new(%inputHash);
    $objects{$col1} = $obj;
}
return values %objects;
它将内容收集到散列中,以消除select中的DUP。问题从注释下方的循环开始,注释中说“问题从这里开始”。我在循环中添加了一条消息,记录每创建100个对象的一行。前100个对象是在5秒内创建的。接下来的100分钟花了16秒。达到300又花了30秒。最多9000个对象,创建100个对象需要12分钟以上的时间。我不认为50000个对象大到足以产生这样的问题

正在创建的Model::Object是一个类,每个属性都有getter和setter。它有一个新方法和一个序列化方法(本质上是toString),就是这样。没有逻辑可言


我在一台Windows笔记本电脑上运行ActiveState Perl 5.16,它有8GB的RAM、一个i7处理器(3年前的)和一个具有合理空间的SSD驱动器。我在Linux机器上看到过同样版本的Perl,所以我认为这不是硬件问题。我需要继续使用5.16版的AS Perl。任何关于如何提高绩效的建议都将不胜感激。谢谢。

首先:介绍您的程序您已经将其缩小为一个子项,使用(例如)您可以将其缩小为罪魁祸首所在的行

以下是我方的一些一般考虑:

只需浏览一下,一些可能的减速因素就会立即浮现在脑海中,但您无法确定是否不评测您的程序

可能哈希分配花费的时间太长。随着
%对象
散列的增长,perl将稳定地分配更多内存。 您可以预先设置
$objects
散列的大小。此功能非常有用。由于这是一个内存分配问题,如果使用太小的数据集配置文件,您将无法识别这一点

# somewhere outside of the loop
keys(%objects) = $number_of_rows * 1.2;
# the hash should be a little bigger than the objects to be stored in it
其次,可能是对象创建时间太长。看看
Model::Object
。我不知道里面有什么,所以我不能对此发表评论。但最肯定的是,您应该考虑通过<代码> %Upthase<代码>作为参考。使用
Model::Object->new(%inputHash)
,将键和值放在堆栈上,然后检索它,最坏的情况是
my%options=@。通过该移动,您可以重新计算每个键的哈希值

也许你能想出一种方法彻底摆脱小的
$inputHash
。我很快只能想出一些方法,这些方法将基于
定义的
网元,但您正在检查真实性(顺便说一句,您确定这是正确的吗?
“0”
是错误的,例如)

但是,最重要的是:分析您的程序。可能需要较小的数据集,但您无法清楚地看到内存分配问题。但是通过评测您将确切地看到,在这一点上,您的程序花费的时间最多


。它也有一个关于分析的好章节。

正如您所读到的,在进行优化之前,必须使用分析工具确定代码中的瓶颈所在。然而,正如我在评论中所描述的,可以以不同的方式重写循环,这样就不会不必要地创建和丢弃未使用的哈希

您还应该看到通过引用而不是作为键和值的简单列表来传递散列的改进

下面是对您的代码的修改,它应该会给您一些想法

use constant COLUMN_NAMES => [ qw/
  col1  col2  col3  col4  col5
  col6  col7  col8  col9  col10
  col11 col12 col13 col14 col15 
/ ];

sub object_results {

    my $dbh = DBI->connect($dsn, $user, $pass);
    my $result_set = $dbh->selectall_arrayref($sql);
    $dbh->disconnect;

    my %objects;
    for ( my $i = $#$result_set; $i >= 0; --$i ) {
        my $row = $result_set->[$i];
        next if exists $objects{$row->[0]};

        my %input_hash;
        for my $i ( 0 .. $#$row ) {
          my $v = $row->[$i];
          next unless defined $v;
          $input_hash{COLUMN_NAMES->[$i]} = $v;
        }

        $objects{$input_hash{col1}} = Model::Object->new(\%input_hash);
    }

    values %objects;
}

您是否在没有创建$obj(甚至%inputHash)的情况下检查了性能?性能问题似乎与哈希有关。如果性能是一个问题,那么您应该转换
my$obj=Model::Object->new(%inputHash)行到我的$obj=\%inputHash
,仅用于测试。再次进行基准测试。如果更改几乎没有影响,那么
Model::Object
就不是您的问题。如果它能带来很大的不同,那么它很可能是。如果您在开始下兔子洞之前对可能的最佳结果有所了解,那么性能调整就更容易实现。据我们所知,真正的问题可能是你用
..
@DavidO传递的代码:虽然我大体上同意你不应该遗漏任何代码,但在这种情况下,周围环境强烈表明,
$inputHash
中只有13个赋值。此外,分析是找到慢行的更好方法,而不是“散弹枪分析”。模型::对象中的结构是什么?你不能简单地说
$objects{$input\u hash{col1}}=bless\%input\u hash,'Model::Object'
而不是调用构造函数吗?您是否始终需要与
col1
的最后一个值对应的数据?如果第一个就可以了,那么你就可以节省大量的工作来构建
%input\u hash
,而它只会被扔掉。您还可以向后迭代
$result\u set
以拾取列表中的最后一个值…最坏的情况是
my%options=@。这样,您就可以为每个关键点重新计算哈希非常好谢谢大家的建议,特别是关于Devel::NYTPRof的建议!我一直在玩它,并发现了一些有趣的结果。我们在所有类中都使用Params::Validate,它被调用的次数非常多,占用的时间最多。所以我在调查我的逻辑是怎么做的。我有一个问题,NYTProf为一个模块返回了一条消息,上面说,“这里看到的影响整个应用程序正则表达式性能的变量”。我