push! showing better performance than pre-allocation for Vector?

I’ll just post the code snippets - they are quite self-explanatory. That said, I am still learning the nitty-gritties of Julia so please bear with me.

vect = Vector{Int}(1000000)
@time for i = 1:1000000
       vect[i] = i
       end
  0.021413 seconds (2.00 M allocations: 30.502 MiB, 4.70% gc time)

vect = Vector{Int}()
@time for i = 1:1000000
       push!(vect,i)
       end
  0.020107 seconds (999.51 k allocations: 24.252 MiB, 6.56% gc time)

push! is taking a little less time AND fewer allocations. What am I missing here? This was on a freshly started Julia REPL. Any help appreciated thanks!

1 Like

These timings are not that representative due to use of global variables. Try wrapping your code in a function.

3 Likes
julia> function foo()
           v = Vector{Float64}(1000000)
           for i = 1:1000000
               v[i] = rand()
           end
           v
       end
foo (generic function with 1 method)

julia> function bar()
           v = Vector{Float64}()
           for i = 1:1000000
               push!(v, rand())
           end
           v
       end
bar (generic function with 1 method)

julia> @btime foo();
  2.827 ms (2 allocations: 7.63 MiB)

julia> @btime bar();
  7.238 ms (20 allocations: 9.00 MiB)
2 Likes

Thanks guys! I do avoid using global variables in general but did not realize that this also affects the timing of these two approaches.

Note also that the rand() call is not that cheap. If instead you assign the elements to 0.0, so that you are just timing the difference in allocation, the difference is larger on my machine: a factor of 7.

Conversely, of course, in a real application where you are performing some expensive computation for each element, the difference in allocation cost will matter less.