# Broadcasting over an anonymous function much slower than map

**URL:** <https://discourse.julialang.org/t/broadcasting-over-an-anonymous-function-much-slower-than-map/34874>\
**Category:** Internals & Design\
**Tags:** performance, broadcasting\
**Created:** [February 19, 2020, 8:09pm UTC](https://discourse.julialang.org/t/broadcasting-over-an-anonymous-function-much-slower-than-map/34874 "2020-02-19T20:09:33Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![bkamins](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bkamins/32/208538_2.png) [@bkamins](https://discourse.julialang.org/u/bkamins)\
**Post date:** [February 19, 2020, 8:09pm UTC](https://discourse.julialang.org/t/broadcasting-over-an-anonymous-function-much-slower-than-map/34874/1 "2020-02-19T20:09:33Z")

</div>

I am on Julia 1.3. I do not understand why broadcasting over an anonymous function is much slower than `map`:

```julia
julia> x1, x2 = rand(10^6), rand(10^6);

julia> @time ((x1, x2) -> x1 < x2).(x1, x2);
  0.265166 seconds (241.28 k allocations: 11.668 MiB, 55.32% gc time)

julia> @time ((x1, x2) -> x1 < x2).(x1, x2);
  0.127725 seconds (241.26 k allocations: 11.668 MiB)

julia> @time ((x1, x2) -> x1 < x2).(x1, x2);
  0.118113 seconds (241.27 k allocations: 11.667 MiB)

julia> @time map((x1, x2) -> x1 < x2, x1, x2);
  0.049027 seconds (75.05 k allocations: 4.463 MiB)

julia> @time map((x1, x2) -> x1 < x2, x1, x2);
  0.039501 seconds (75.05 k allocations: 4.462 MiB)

julia> @time map((x1, x2) -> x1 < x2, x1, x2);
  0.060107 seconds (75.07 k allocations: 4.466 MiB, 13.32% gc time)

```

Notes:

1. if anonymous function is defined in inner scope (e.g. within a function) this does not happen
2. if anonymous function is passed as an argument to a function and used in this function then this does still happen  
(for normal functions this is not the case)
3. this does not happen for normal functions

CC  
@nalimilan - this is related to auto-splatting design  
@mbauman - maybe you know the answer immediately (or this question has been asked)

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [February 19, 2020, 8:25pm UTC](https://discourse.julialang.org/t/broadcasting-over-an-anonymous-function-much-slower-than-map/34874/2 "2020-02-19T20:25:13Z")

</div>

It’s simply due to using `@time` at global scope. Every time you write an anonymous function, Julia creates a new type (and I mean “write” literally — it’s a syntax thing). This means that repeatedly `@time`ing an expression that includes a newly written anonymous function will result in compilation overhead.

As you might imagine, there’s a bigger compilation overhead for broadcasting than there is for map.

```nohighlight
julia> x1, x2 = rand(10^6), rand(10^6);

julia> @time ((x1, x2) -> x1 < x2).(x1, x2);
  0.108282 seconds (305.77 k allocations: 15.174 MiB, 5.31% gc time)

julia> @time map((x1, x2) -> x1 < x2, x1, x2);
  0.081244 seconds (249.05 k allocations: 13.298 MiB)

julia> f1(x1, x2) = ((x1, x2) -> x1 < x2).(x1, x2)
f1 (generic function with 1 method)

julia> f2(x1, x2) = map((x1, x2) -> x1 < x2, x1, x2)
f2 (generic function with 1 method)

julia> @time f1(x1, x2);
  0.075796 seconds (274.78 k allocations: 13.131 MiB, 6.82% gc time)

julia> @time f1(x1, x2);
  0.002112 seconds (8 allocations: 126.578 KiB)

julia> @time f2(x1, x2);
  0.031752 seconds (81.93 k allocations: 4.838 MiB)

julia> @time f2(x1, x2);
  0.002374 seconds (9 allocations: 976.922 KiB)

```

Better to use BenchmarkTools, in general.

---

<div class="post-metadata">

**Author:** ![bkamins](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bkamins/32/208538_2.png) [@bkamins](https://discourse.julialang.org/u/bkamins)\
**Post date:** [February 19, 2020, 8:39pm UTC](https://discourse.julialang.org/t/broadcasting-over-an-anonymous-function-much-slower-than-map/34874/3 "2020-02-19T20:39:53Z")

</div>

Right - thank you! I need to use `@time` because I am also interested in timings that include compilation overhead.

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [February 19, 2020, 11:29pm UTC](https://discourse.julialang.org/t/broadcasting-over-an-anonymous-function-much-slower-than-map/34874/4 "2020-02-19T23:29:31Z")

</div>

Yeah, you can see this even with the simple:

```julia
julia> a = ()->nothing
#7 (generic function with 1 method)

julia> b = ()->nothing
#9 (generic function with 1 method)

julia> a === b
false

julia> typeof(a) === typeof(b)
false

```

So when you pass a newly written anonymous function to a function, there will be some new compilation — even if you passed the syntactically identical anonymous function before — because the newly written one has a new type.

There’s a possible future optimization that would identify syntactically identical anonymous functions to re-use the same types when possible (although perhaps just at the REPL [#21113](https://github.com/JuliaLang/julia/issues/21113)),

---

<div class="post-metadata">

**Author:** ![pablosanjose](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pablosanjose/32/7006_2.png) [@pablosanjose](https://discourse.julialang.org/u/pablosanjose)\
**Post date:** [February 21, 2020, 5:35pm UTC](https://discourse.julialang.org/t/broadcasting-over-an-anonymous-function-much-slower-than-map/34874/5 "2020-02-21T17:35:56Z")

</div>

Note that, by the same token, you can use anonymous functions without incurring compile overhead more than once in the global scope by simply preassigning them:

```julia
julia> x1, x2 = rand(10^6), rand(10^6);

julia> f = (x1, x2) -> x1 < x2
#3 (generic function with 1 method)

julia> @time f.(x1, x2);
  0.198223 seconds (435.04 k allocations: 20.128 MiB, 10.93% gc time)

julia> @time f.(x1, x2);
  0.001045 seconds (6 allocations: 126.469 KiB)

julia> @time map(f, x1, x2);
  0.088391 seconds (248.75 k allocations: 13.249 MiB)

julia> @time map(f, x1, x2);
  0.002658 seconds (5 allocations: 976.766 KiB)

```

Then broadcast can be faster than `map`
