【发布时间】:2021-04-30 01:17:27
【问题描述】:
eval 处理字符串时速度很慢:必须先解析字符串才能执行。
我正在寻找一种缓存解析的方法,以便我可以将解析的字符串重用于另一个 eval。下一个 eval 将是相同的代码,但不会 eval 为相同的值,所以我不能简单地缓存结果。
从描述中我正在寻找来自Eval::Compile的ceval。
但我不能使用 Eval::Compile,因为这需要平台的 C 编译器,而且用户没有 C 编译器。
那么我可以在纯 Perl 中做类似于 ceval 的事情吗?
背景
GNU Parallel 允许用户给出将在每个参数上进行评估的 Perl 表达式。目前,Perl 表达式由用户以字符串形式给出,并对每个参数进行评估。 Perl 表达式对于每个参数保持不变。因此重新编译表达式是一种浪费,因为重新编译不会改变任何东西。
代码分析表明eval 是瓶颈之一。
示例
用户输入:$_ .= "foo" and s/a/b/g
用户的脚本存储在$usereval1 和$usereval2。
用户给出存储在@arguments中的10000个随机参数(字符串)。
sub replace {
my ($script, $arg) = @_;
local $_;
$_ = $arg;
# This is where I would like to cache the parsed $script.
eval $script;
return $_;
}
for my $arg (@arguments) {
# Loads of indirect code (in the order of 1000 lines) that
# call subs calling subs calling subs that eventually does:
$replaced1 = replace($usereval1, $arg);
$replaced2 = replace($usereval2, $arg);
# Yet more code that does stuff with $replaced1 $replaced2
}
【问题讨论】:
-
每次调用到底有什么不同?
-
你可以像这样存储一个子程序引用:
perl -lwe 'my $x = eval(q( sub { my $foo = shift; $foo*2; } )); print $x->(12);'打印24。但是这就引出了一个问题,写一个子程序不是更简单吗?你确定你需要动态代码,还是这只是一个蛮力解决方案?如果您想要更好的答案,您需要分享有关您的解决方案的更多详细信息。 -
用户提供要评估的表达式,所以是的,我需要动态代码。制作匿名潜艇并不是一个坏主意。还是更快吗?你量过吗?如果是这样,你能公布你的数字吗?
-
@TLP 我做了一个最小的测试。它看起来好像快了 40 倍。太好了!
-
@OleTange 允许用户向
eval提供代码听起来像是一个非常危险的想法。即使假设人们没有积极尝试恶意,你也知道有人最终会破坏某些东西。如果我是你,我会花更多的时间来找出一个安全的方法来做到这一点。