On Thu Jun 25 12:02:54 2020, HVDS wrote:
Show quoted text> Can it be fixed?
Yes and no. It largely depends what you mean "fixed".
The various List::Util list-iteration functions all use a little-known core perl feature called MULTICALL, which is a performance enhancement for functions which just invoke a supplied sub body repeatedly, as reduce, any/all/etc.. all do. MULTICALL basically arranges to do the ENTERSUB parts of the call, but stops before the optree is actually executed, returning control to the XS function (e.g. reduce). That can then run the actual body repeatedly, before finally doing the LEAVESUB step just once at the end, after it has finished. Overall this performance optimisation aims to make the whole operation run faster, by not having to repeatedly ENTERSUB/LEAVESUB for every element.
The downside of doing it that way is, as you observe, the other side-effects of ENTERSUB/LEAVESUB don't get to clean up inbetween, so things like pad reset don't happen.
There's basically three ways around this:
1) Just stop using MULTICALL at all
This would have quite the performance impact on any existing code
currently using these functions. The entire reason MULTICALL was
originally invented was to avoid this.
2) Recreate the pad-clearing steps of ENTERSUB/LEAVESUB into the XS
functions such as reduce, any/all,...
We'd want to study the performance impact of even doing this.
Obviously, the more that these functions have to recreate differently
from what ENTERSUB/LEAVESUB do, the more code duplication there is and
the worse the performance gets. Taken to the ultimate extreme, we'd end
up copying all of the logic and thus be no better than option 1 in
terms of performance, but at a significant downside to code complexity.
0) Leave it as it is, and document "don't do this"
Currently we have taken option 0. If you think we should take options 1 or 2 instead, I'd first like to see some benchmarking of the relative performance overheads those would entail; especially as they are likely to be dominant factors in the typical small cases such as
any { $_ eq "something } @items
There is, on the horizon, a third option.
I have plans to create a better version of these list utilities which would operate on a lower level, being parsed as real keywords and operating at the same level as e.g. map and grep, so the BLOCK is not a separate function and thus no ENTERSUB/LEAVESUB logic needs to take place. It wouldn't be possible to simply provide these instead of the regular ones, because code such as
reduce { return $a+$b } @numbers
would suddenly behave very differently. Instead, they'd be in a new XS module in a new name, with the eventual hope to become real core syntax eventually.
--
Paul Evans