# Pre-allocating array efficiency

**URL:** <https://discourse.julialang.org/t/pre-allocating-array-efficiency/121207>\
**Category:** Performance\
**Created:** [October 11, 2024, 8:59pm UTC](https://discourse.julialang.org/t/pre-allocating-array-efficiency/121207 "2024-10-11T20:59:49Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![miguelborrero](https://avatars.discourse-cdn.com/v4/letter/m/eb9ed0/32.png) [@miguelborrero](https://discourse.julialang.org/u/miguelborrero)\
**Post date:** [October 11, 2024, 8:59pm UTC](https://discourse.julialang.org/t/pre-allocating-array-efficiency/121207/1 "2024-10-11T20:59:49Z")

</div>

Hi there,

my understanding was, in vague terms, that pre-allocating an array by specifying size and then populating the elements of that array was more efficient than defining an array without doing so. To test this I just benchmarked examples of these two methods:

```julia
function no_preallocation()
    mat = []
    for i in 1:1000
        push!(mat, rand(1000))
    end
end

```

with benchmark results:

 ![Captura de pantalla 2024-10-11 a la(s) 13.58.52](https://global.discourse-cdn.com/julialang/original/3X/0/e/0e5d14971fb703596b5ea5a514f5a3c152d59c60.png)

and

```julia
function preallocation()
    mat = Array{Float64}(undef, 1000, 1000)
    for i in 1:1000
        mat[i, :] = rand(1000)
    end
end

```

with benchmark:

 ![Captura de pantalla 2024-10-11 a la(s) 13.59.31](https://global.discourse-cdn.com/julialang/original/3X/1/7/179f4e4bac33528397c8da3baf94ae4dbf3b0454.png)

so it seems that my intuition was wrong.

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [October 11, 2024, 9:05pm UTC](https://discourse.julialang.org/t/pre-allocating-array-efficiency/121207/2 "2024-10-11T21:05:50Z")

</div>

The comparison should be to

```julia
function preallocation()
    mat = Array{Float64}(undef, 1000)
    for i in 1:1000
        mat[i] = rand(1000)
    end
end

```

Your comparison is copying the vectors.

---

<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 11, 2024, 9:38pm UTC](https://discourse.julialang.org/t/pre-allocating-array-efficiency/121207/3 "2024-10-11T21:38:25Z")

</div>

Note also that you are comparing two totally different data structures (an 1d array of 1d arrays ≠ a 2d array). And by including `rand(1000)` calls in your benchmark, a big chunk of the timing is due to generating random numbers.

> [@Oscar\_Smith](#):
>
> `mat = Array{Float64}(undef, 1000)`

I think you mean `Array{Vector{Float64}}(undef, 1000)`

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [October 11, 2024, 10:33pm UTC](https://discourse.julialang.org/t/pre-allocating-array-efficiency/121207/4 "2024-10-11T22:33:52Z")

</div>

Your first, non-pre-allocated benchmark, uses untyped collections: `mat = []`. Make sure to use a type annotation, like

```julia
mat = Vector{Float64}[] 

```

Your second benchmark does not properly pre-allocate. A new vector is allocated on each iteration. Try something like

```julia
mat[:, i] .= rand.()

```

Warning: untested. But note the changed dimensionality, work along columns, not rows.

Or even better, do

```julia
mat .= rand.() # or rand!(mat) 

```

removing the loop.

Also, much of the time is used on the rand call itself.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [October 11, 2024, 11:57pm UTC](https://discourse.julialang.org/t/pre-allocating-array-efficiency/121207/5 "2024-10-11T23:57:33Z")

</div>

Helps to count the allocations in your code:

```julia
function no_preallocation()
    mat = [] # allocates Vector{Any}
    for i in 1:1000 # 1000 times
        # push! reallocates mat for some resizes
        # rand(1000) allocates 1000-element Vector{Float64}
        push!(mat, rand(1000))
    end
end
# at least 1001 allocations, your @benchmark shows 1006

function preallocation()
    mat = Array{Float64}(undef, 1000, 1000) # self-explanatory
    for i in 1:1000 # 1000 times
        mat[i, :] = rand(1000) # allocates 1000-element Vector{Float64}
    end
end
# at least 1001 allocations, your @benchmark shows 1002

```

So you didn’t significantly save allocations overall, you trimmed a few resizing allocations in `push!`. As others have said, your data structures and element types also differ, so even putting the similar allocation count aside, it is not a fair comparison for performance either.

Also worth mentioning that `rand(1000)` has gone from 1 allocation in v1.10.5 to 3 allocations in v1.11.0, albeit with less memory overall, due to the changes to `Array`’s implementation.

---

<div class="post-metadata">

**Author:** ![miguelborrero](https://avatars.discourse-cdn.com/v4/letter/m/eb9ed0/32.png) [@miguelborrero](https://discourse.julialang.org/u/miguelborrero)\
**Post date:** [October 12, 2024, 4:52pm UTC](https://discourse.julialang.org/t/pre-allocating-array-efficiency/121207/6 "2024-10-12T16:52:22Z")

</div>

I see, I think the different data structures effect was causing the issue. Once I corrected for this the preallocation benchmark improved the alternative. I thought they where the same structure. Thanks a lot!
