I believe eval puts the function in global scope and thus has complete type information on the function. Your second attempt takes in a "Function" type which could be anything, and thus the compiler can't specialize very much. This problem may eventually go away if the Function type can be parametized with input and output type information.
On Thu, Jul 16, 2015 at 11:22 AM, David Gold <[email protected]> wrote: > Suppose I want to apply the trick that makes `broadcast!` fast to `map!`. > Because of the specificity of `map!`'s functionality, I don't necessarily > need to cache the internally declared functions, so I just write: > > function map!{F}(f::F, dest::AbstractArray, src::AbstractArray) > _f = Expr(:quote, f) > @eval begin > function func(dest, A) > for i in 1:length(dest) > dest[i] = $_f(A[i]) > end > end > func($dest, $A) > return $dest > end > end > > which does indeed show improved performance: > > srand(1) > N = 5_000_000 > A = rand(N) > X = Array(Float64, N) > f(x) = 5 * x > map!(f, X, A); > > *julia> **map!(f, X, A);* > > > *julia> **@time map!(f, X, A);* > > 17.459 milliseconds (2143 allocations: 109 KB) > > > *julia> **Base.map!(f, X, A);* > > > *julia> **@time Base.map!(f, X, A);* > > 578.520 milliseconds (19999 k allocations: 305 MB, 6.45% gc time) > > > Okay. But the following attempt does not experience the same speedup: > > > function map!{F}(f::F, dest::AbstractArray, src::AbstractArray) > > function func(dest, A) > > for i in 1:length(dest) > > dest[i] = f(A[i]) > > end > > end > > func(dest, A) > > return dest > > end > > > *julia> **map!(f, X, A);* > > > *julia> **@time map!(f, X, A);* > > 564.823 milliseconds (20000 k allocations: 305 MB, 6.44% gc time) > > > My question is: Why is `eval`-ing the body of `map!` necessary for > supporting the type inference/other optimizations that give the first > revised `map!` method greater performance? I suspect that there's something > about what `eval` does, aside from just "evaluate an expression" that I'm > not quite grokking -- but what? Also, what risks in particular does > invoking `eval` at runtime inside the body of a function -- as opposed to > directly inside the global scope of a module -- pose? > > > Thanks, > > D > > >
