Hello everyone. The following simple example is just to ask the question: will Julia evaluate the length function 5 times? Thank you.
function test()
v = [1,2,3,4,5]
for i = 1:length(v)
println(v[i])
end
end
Hello everyone. The following simple example is just to ask the question: will Julia evaluate the length function 5 times? Thank you.
function test()
v = [1,2,3,4,5]
for i = 1:length(v)
println(v[i])
end
end
No
A quick and no-brainer way to check if performance is affected (while not answering your question exactly):
using BenchmarkTools
v = [1:10_000]
function test1(v)
for i = 1:length(v)
println(v[i])
end
end
@btime test1(v)
120.894 ÎĽs (22 allocations: 800 bytes)
function test2(v)
n = length(v)
for i = 1:n
println(v[i])
end
end
@btime test2(v)
121.065 ÎĽs (22 allocations: 800 bytes)
The key thing to understand here is that 1:length(v) is just an ordinary Julia expression that creates a “range” object storing the endpoints. This object gets evaluated once, before the for loop starts, and gets re-used on every iteration as needed.
More generally, whenever you do for x = X or (equivalently) for x in X, for any expression X, the expression X is evaluated once and then the resulting iterable object is re-used during the loop.
I only knew @time, I liked @btime, very good!
I tend to avoid the combination of @btime and println. How far do you have to scroll back up to compare the results?
In the OP’s code, it’s just something to do inside the loop.
julia> length(v)
1
Though your example is still valid perhaps you meant v=[i for i in 1:10_000]?
perhaps you meant
v=[i for i in 1:10_000]?
I meant something big that’s all.
You can see it explicitely with:
julia> function test()
v = [1,2,3,4,5]
for i = 1:length(v)
println(v[i])
end
end
test (generic function with 1 method)
julia> @code_lowered test()
CodeInfo(
1 ─ v = Base.vect(1, 2, 3, 4, 5)
│ %2 = Main.length(v)
│ %3 = 1:%2
│ @_2 = Base.iterate(%3)
│ %5 = @_2 === nothing
│ %6 = Base.not_int(%5)
└── goto #4 if not %6
2 ┄ %8 = @_2
│ i = Core.getfield(%8, 1)
│ %10 = Core.getfield(%8, 2)
│ %11 = Base.getindex(v, i)
│ Main.println(%11)
│ @_2 = Base.iterate(%3, %10)
│ %14 = @_2 === nothing
│ %15 = Base.not_int(%14)
└── goto #4 if not %15
3 ─ goto #2
4 ┄ return nothing
)