Perl: Speeding up eval

2019-04-02 02:34发布

eval is slow when done on a string: The string first has to be parsed before it can be executed.

I am looking for a way to cache the parsing, so that I can reuse the parsed string for yet another eval. The next eval will be the same code but will not eval to the same value, so I cannot simply cache the results.

From the description I am looking for ceval from: https://metacpan.org/pod/Eval::Compile

But I cannot use Eval::Compile, as that requires a C-compiler for the platform, and it is not given that the user has a C-compiler.

So can I do something similar to ceval in pure perl?

Background

GNU Parallel lets the user give perl expressions that will be eval'ed on every argument. Currently the perl expressions are given as strings by the user and eval'ed for every argument. The perl expressions remain unchanged for each argument. It is therefore a waste to re-compile the expression as the re-compilation will not change anything.

Profiling of the code shows that the eval is one of the bottlenecks.

Example

The user enters: $_ .= "foo" and s/a/b/g

User's scripts are stored in $usereval1 and $usereval2

The user gives 10000 random arguments (strings) stored in @arguments.

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 eval
1条回答
仙女界的扛把子
2楼-- · 2019-04-02 02:59

Posting comment as answer per request:

You can store a subroutine ref like this:

perl -lwe 'my $x = eval(q( sub { my $foo = shift; $foo*2; } )); print $x->(12);' 

This prints 24. You can re-use the code without the need to recompile it.

查看更多
登录 后发表回答