Why are my higher order functions a million times slower than they should be?

Ah, ok. The thing is that Julia does not specialize for the function type if the function is not called from withing the function. Thus, the fix is:

ulia> function slow(f::F, x) where F # annotate F type here !
           y = apply(f, x)
           for _ in eachindex(y)
               
           end
       end
slow (generic function with 1 method)

julia> function run()
           for f in [slow, fast]
               x = rand(10^6)
               @time f(identity, x)
           end
       end
run (generic function with 1 method)

julia> run()
  0.003013 seconds (3.17 k allocations: 170.994 KiB, 99.51% compilation time)
  0.000002 seconds

julia> run()
  0.000009 seconds
  0.000005 seconds

This is actually the performance tip to be considered here (a tricky one, I learnt this the hard way as well):

https://docs.julialang.org/en/v1/manual/performance-tips/#Be-aware-of-when-Julia-avoids-specializing

6 Likes