记住 XML 解析函数会破坏它

memoizing an XML parsing function breaks it

提问人:Emilio M Bumachar 提问时间:8/20/2020 更新时间:8/20/2020 访问量:58

问:

我是Perl的新手,我需要提高别人编写的应用程序的性能。

分析表明,该程序在 XML::Simple 库中花费了大量时间。 根据对应用程序的使用如何随时间变化的了解,我们怀疑它正在多次重新分析相同的 XML 数据。

记住 XML 解析函数似乎是一个简单的修复方法。假定它从中获取 XML 数据的文件在程序运行时不会更改,因此我们只缓存每个文件的结果。

这种函数是库的入口点,是 XMLin。

我对软件的唯一更改是添加

use Memoize;
memoize('XMLin');

尝试运行将返回错误:

    Not a HASH reference at C:\QuEST\Scripts\RangeAnalyzer/ParseETP.pl line 269.

第 269 行是:

@constantElements = @{$xml->{declarations}->{Package}->{declarations}->{Constant}};
    

...并定义为:$xml

my $xml = XMLin($Filename, KeyAttr => {ConstValue => '', Operator => '', VariableRef => '', Variable => '', StateMachine => '', State => '', IfBlock => '', WhenBlock => '', SizeParameter => ''}, ForceArray => ['Variable', 'ConstValue', 'DataArrayOp', 'Constant']);

撤消更改可修复错误。

为什么记忆函数会破坏其返回值?如何解决?

我注意到它已被弃用,并且最好用更快的东西替换它,这是要尝试的事情之一。 然而,这个错误打破了我关于记忆应该如何工作的心理模型。XML::Simple

我正在使用 Perl 5.10.0。

Perl XML 解析 记忆

评论

0赞 ikegami 8/20/2020
您能否提供该问题的最小、可运行的演示?
0赞 A Gold Man 8/20/2020
另外,也许您可以在出错之前显示包含该行的内容?Data::Dumper$xml
1赞 Grant McLean 8/20/2020
不确定是什么破坏了你的代码,但即使 memoize 确实有效,值得指出的是,您为该选项传递的值是使用匿名 hashref 构造函数,它将在每次执行时返回对不同的、新构造的 hashref 的引用。因此,记忆函数在每次调用时都会看到不同的参数值,并且不会从缓存中返回值。KeyAttr{...}
2赞 ikegami 8/20/2020
我怀疑这个错误与 无关,仅仅是因为代码与 XML 不匹配。XML::Simple 是最复杂的 XML 解析器。到目前为止。不要使用它!memoize
1赞 ikegami 8/20/2020
@A Gold Man,Re “OP 不需要飞过可能相关也可能不相关的线”,是的,他们确实如此。我们的“工作”不是处理大量不相关的数据。他们确实需要为问题生成一个最小的、可运行的演示。此外,将 XML 文件砍减为包含“查询”中元素的位是微不足道的,并且他们已经提供了用于加载 XML 文件的代码。

答:

2赞 A Gold Man 8/20/2020 #1

恐怕您的问题中没有足够的信息来完全回答出了什么问题。(至少在有 MWE 之前不会)。但是,我想指出您可能需要考虑的两件事。

为了记住一个函数,Memoize 使用归一化器来检查参数是否相同。根据文档,默认情况下,这只会字符串化参数。这意味着 hashref 被转换为其字符串表示形式,即它在内存中的位置。这将在函数的调用之间发生变化,因此它永远不会正确地识别您传递了相同的参数。

您可能希望提供自己的规范化函数来处理 XML::Simple 所需的特定参数样式。

此外,根据文档中的警告部分,如果您的函数返回引用,则返回相同的引用。这意味着,如果您在某个时候修改了结构(鉴于给定的信息,我无法知道是否发生这种情况),那么修改后的结构将在稍后返回。

评论

0赞 ikegami 8/20/2020
如果它们始终传递文件名和相同的选项,则自定义规范化函数可以简单地返回第一个参数(文件名)。如果它们总是传递文件名,但并不总是相同的选项,那么 using 应该可以解决问题。Cpanel::JSON::XS->new->canonical->encode(\@_)