# Map vs Loops & Array Comprehensions in Julia 1.0

**URL:** https://discourse.julialang.org/t/map-vs-loops-array-comprehensions-in-julia-1-0/16137
**Category:** Performance
**Created:** [October 10, 2018, 9:00pm UTC](https://discourse.julialang.org/t/map-vs-loops-array-comprehensions-in-julia-1-0/16137 "2018-10-10T21:00:53Z")
**Posts on this page:** 11
**Page:** 1

<div class="post-metadata">

### Author: ![mdsalerno](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mdsalerno/32/5539_2.png) [@mdsalerno](https://discourse.julialang.org/u/mdsalerno)
#### Post date: [October 10, 2018, 9:00pm UTC](https://discourse.julialang.org/t/map-vs-loops-array-comprehensions-in-julia-1-0/16137/1 "2018-10-10T21:00:53Z")

</div>

I’ve seen some older threads on this topic, but is it still the case that loops and array comprehensions are significantly faster than map() in Julia 1.0? If so, can someone provide intuition into why this is the case. Any examples of when we might want to use map() if array comprehensions are generally more efficient?

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [October 10, 2018, 10:22pm UTC](https://discourse.julialang.org/t/map-vs-loops-array-comprehensions-in-julia-1-0/16137/2 "2018-10-10T22:22:09Z")

</div>

In general, `map` is as fast as handwritten loops these days: higher-order functions like this have been inlined and compiled to fast code since Julia 0.5. For example:

```julia
using BenchmarkTools

fmap(x) = map(x -> 2x, x)
fcomprehension(x) = [2x for x in x]
fdot(x) = 2 .* x
function floop(x)
    y = similar(x)
    for i in eachindex(x)
        y[i] = 2*x[i]
    end
    return y
end
function floopopt(x)
    y = similar(x)
    @simd for i in eachindex(x)
        @inbounds y[i] = 2*x[i]
    end
    return y
end

x = rand(1000)
@btime fmap($x)
@btime fcomprehension($x)
@btime fdot($x)
@btime floop($x)
@btime floopopt($x);

```

gives

```julia
  551.676 ns (2 allocations: 7.95 KiB)
  524.476 ns (2 allocations: 7.95 KiB)
  559.751 ns (1 allocation: 7.94 KiB)
  764.900 ns (1 allocation: 7.94 KiB)
  579.556 ns (1 allocation: 7.94 KiB)

```

with Julia 1.0 on my machine: the loops are actually slightly slower unless you use some tricks.

---

<div class="post-metadata">

### Author: ![tbeason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tbeason/32/15898_2.png) [@tbeason](https://discourse.julialang.org/u/tbeason)
#### Post date: [October 10, 2018, 10:24pm UTC](https://discourse.julialang.org/t/map-vs-loops-array-comprehensions-in-julia-1-0/16137/3 "2018-10-10T22:24:49Z")

</div>

This was actually a really useful Q and A.

---

<div class="post-metadata">

### Author: ![mdsalerno](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mdsalerno/32/5539_2.png) [@mdsalerno](https://discourse.julialang.org/u/mdsalerno)
#### Post date: [October 10, 2018, 10:58pm UTC](https://discourse.julialang.org/t/map-vs-loops-array-comprehensions-in-julia-1-0/16137/4 "2018-10-10T22:58:50Z")

</div>

Really stoked to learn this! Thanks for the example and clarification.

---

<div class="post-metadata">

### Author: ![emmt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/emmt/32/5192_2.png) [@emmt](https://discourse.julialang.org/u/emmt)
#### Post date: [February 25, 2021, 3:54pm UTC](https://discourse.julialang.org/t/map-vs-loops-array-comprehensions-in-julia-1-0/16137/5 "2021-02-25T15:54:03Z")

</div>

The timings include the time spent for allocating the result and for computing it. I would suggest using a larger number of elements to focus on computations. For instance, starting with the same code as above by @stevengj but with:

```julia
x = rand(10000);

```

yields:

```julia
julia> @btime fmap($x);
  4.119 μs (2 allocations: 78.20 KiB)

julia> @btime fcomprehension($x);
  6.006 μs (2 allocations: 78.20 KiB)

julia> @btime fdot($x);
  6.160 μs (2 allocations: 78.20 KiB)

julia> @btime floop($x);
  7.613 μs (2 allocations: 78.20 KiB)

julia> @btime floopopt($x);
  6.298 μs (2 allocations: 78.20 KiB)

```

on my machine (AMD Ryzen Threadripper 2950X 16-Core Processor) with Julia 1.5 and -O3 optimization. This shows that `map!` is significantly faster on large arrays. With 1000 elements as in the original example, the timings are all very silmilar (between 830.247 ns for `fcomprehension` to 867.000 ns for `floop`).

---

<div class="post-metadata">

### Author: ![nilshg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nilshg/32/2283_2.png) [@nilshg](https://discourse.julialang.org/u/nilshg)
#### Post date: [February 25, 2021, 4:39pm UTC](https://discourse.julialang.org/t/map-vs-loops-array-comprehensions-in-julia-1-0/16137/6 "2021-02-25T16:39:40Z")

</div>

For a

```julia
julia> versioninfo()
Julia Version 1.6.0-beta1.0
Commit b84990e1ac (2021-01-08 12:42 UTC)
Platform Info:
  OS: Windows (x86_64-w64-mingw32)
  CPU: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz

```

I get

```julia
julia> x = rand(10_000);

julia> @btime fmap($x);
  5.380 μs (2 allocations: 78.20 KiB)

julia> @btime fcomprehension($x);
  5.380 μs (2 allocations: 78.20 KiB)

julia> @btime fdot($x);
  5.100 μs (2 allocations: 78.20 KiB)

julia> @btime floop($x);
  8.300 μs (2 allocations: 78.20 KiB)

julia> @btime floopopt($x);
  5.180 μs (2 allocations: 78.20 KiB)

```

in line with the results from 2 years ago.

---

<div class="post-metadata">

### Author: ![Skoffer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/skoffer/32/378_2.png) [@Skoffer](https://discourse.julialang.org/u/Skoffer)
#### Post date: [February 25, 2021, 4:43pm UTC](https://discourse.julialang.org/t/map-vs-loops-array-comprehensions-in-julia-1-0/16137/7 "2021-02-25T16:43:53Z")

</div>

Interesting, it looks like something strange is going on with something. On my laptop (Intel(R) Core™ i7-7700HQ CPU @ 2.80GHz) with Julia 1.7 I get (running consequently)

```julia
julia> @btime floopopt($x);
  7.161 μs (2 allocations: 78.20 KiB)

julia> @btime fmap($x);
  4.601 μs (2 allocations: 78.20 KiB)

julia> @btime floopopt($x);
  4.338 μs (2 allocations: 78.20 KiB)

julia> @btime fmap($x);
  6.514 μs (2 allocations: 78.20 KiB)

```

So, for some reason timing is very unstable.

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [February 25, 2021, 4:46pm UTC](https://discourse.julialang.org/t/map-vs-loops-array-comprehensions-in-julia-1-0/16137/8 "2021-02-25T16:46:47Z")

</div>

> [@nilshg](#):
>
> in line with the results from 2 years ago.

On my machine with Julia 1.6 the `-O3` makes a big difference for the `fmap` time.

---

<div class="post-metadata">

### Author: ![nilshg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nilshg/32/2283_2.png) [@nilshg](https://discourse.julialang.org/u/nilshg)
#### Post date: [February 25, 2021, 5:17pm UTC](https://discourse.julialang.org/t/map-vs-loops-array-comprehensions-in-julia-1-0/16137/9 "2021-02-25T17:17:46Z")

</div>

Hm, doesn’t seem to matter for me - the above was without flags (which I think is O2?), I had absorbed somewhere on here that O3 basically doesn’t actually do any worthwhile optimizations anymore:

```julia
C:\Users\ngudat>julia -O3

(...)

julia> x = rand(10_000);

julia> @btime fmap($x);
  5.980 μs (2 allocations: 78.20 KiB)

julia> @btime fcomprehension($x);
  6.050 μs (2 allocations: 78.20 KiB)

julia> @btime fdot($x);
  5.433 μs (2 allocations: 78.20 KiB)

julia> @btime floop($x);
  8.100 μs (2 allocations: 78.20 KiB)

julia> @btime floopopt($x);
  5.450 μs (2 allocations: 78.20 KiB)

```

---

<div class="post-metadata">

### Author: ![emmt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/emmt/32/5192_2.png) [@emmt](https://discourse.julialang.org/u/emmt)
#### Post date: [February 26, 2021, 5:44pm UTC](https://discourse.julialang.org/t/map-vs-loops-array-comprehensions-in-julia-1-0/16137/10 "2021-02-26T17:44:04Z")

</div>

These large variations in the timings of @Skoffer are surprising. Perhaps there were some other heavy tasks running?

Otherwise, from all timings, it seems that `fmap` is among the fastest and yet very simple (just a call to `map`). This is something I definitively like with Julia: simple things oftenly turn out to be the most efficient.

---

<div class="post-metadata">

### Author: ![Storopoli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/storopoli/32/209278_2.png) [@Storopoli](https://discourse.julialang.org/u/Storopoli)
#### Post date: [March 3, 2021, 7:41am UTC](https://discourse.julialang.org/t/map-vs-loops-array-comprehensions-in-julia-1-0/16137/11 "2021-03-03T07:41:49Z")

</div>

MacBook Air M1 Julia 1.7.0 compiled from source running native in Arm for `x = 1_000`:

```julia
julia> @btime fmap($x);
  1.408 μs (2 allocations: 78.20 KiB)

julia> @btime fcomprehension($x);
  1.417 μs (2 allocations: 78.20 KiB)

julia> @btime fdot($x);
  1.204 μs (2 allocations: 78.20 KiB)

julia> @btime floop($x);
  5.132 μs (2 allocations: 78.20 KiB)

julia> @btime floopopt($x);
  1.208 μs (2 allocations: 78.20 KiB)

```
