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
}
Posting comment as answer per request:
You can store a subroutine ref like this:
This prints
24
. You can re-use the code without the need to recompile it.