Consider the example, in which I want to perform some calculations on a part of vector:
julia> f( x :: Vector{Float64} ) = (x[1]^2 + x[2]^2 + x[3]^2)
f (generic function with 1 method)
julia> g( x :: AbstractArray ) = (x[1]^2 + x[2]^2 + x[3]^2)
g (generic function with 1 method)
julia> x = rand(10) ;
julia> @btime f(x[1:3])
36.707 ns (1 allocation: 112 bytes)
0.5715412873805833
julia> @btime g(@view(x[1:3]))
31.029 ns (2 allocations: 64 bytes)
0.5715412873805833
julia> @btime g(x[1:3])
51.352 ns (2 allocations: 128 bytes)
0.5715412873805833
The question is: the optimal choice appears to allow abstract arrays into the function, and pass on βviewsβ. However, if the input vector is not a subarray, the computation using the explicit declaration of the type (Vector{Float64}
) results in faster calculations:
julia> y = rand(3);
julia> @btime f(y)
3.808 ns (0 allocations: 0 bytes)
0.6112547604892745
julia> @btime g(y)
15.278 ns (1 allocation: 16 bytes)
0.6112547604892745
The βproblemβ is that the function with the explicit declaration of the type of vector does not accept views as input. I am not sure how to deal with this situation, except by duplicating the functions, but it not clear to me which function will be called in each case, in a situation like this:
julia> f( x :: AbstractArray ) = (x[1]^2 + x[2]^2 + x[3]^2)
f (generic function with 2 methods)
julia> f( x :: Vector{Float64} ) = (x[1]^2 + x[2]^2 + x[3]^2)
f (generic function with 2 methods)
julia> x = rand(3);
julia> @btime f(x)
7.033 ns (1 allocation: 16 bytes)
0.6452099587041162
julia> @btime f(x[1:3])
44.356 ns (2 allocations: 128 bytes)
0.6452099587041162
julia> @btime f(@view(x[1:3]))
34.107 ns (2 allocations: 64 bytes)
0.6452099587041162
Edit: is seems, from the allocations, that the function accepting Abstract arrays is being called in all three cases in this last example. Thus, the function with the explicit declaration is not used at all, and one looses performance.