Let me try to summarize (because there is a lot of confusion around this):
-
Your initial approach is fine in terms of performance.
“Avoid global variables” means avoid inheriting global variables through scoping. Your code will use global variables as inputs and outputs; this is normal.
F1!()could have been defined without taking any arguments and still work. Then it would have to obtain the values from the outer (in this case global) scope. That would be bad practice and slow unless those variables are declared to beconst. Theconstapproach is intended for actual constants that are fixed across all simulations (none of your variables). It is useful becauseconstvariables are inherently known to all functions and are still fast to use. Link -
You don’t need to allocate
R1andR2in your example. Just callranddirectly.
F1!(V, P, G, i) = @. V[:,i] = rand()*(@view P[:,i]) + rand() * G -
You could better organize your function inputs to be more readable.
- Do not pass array sizes as arguments.
sizeis very cheap to compute, so passingnandNalongside the arrays themselves just makes your code harder to read and more error prone. You should write the loop (no longer needed) asfor j in eachindex(G). Then you don’t neednat all: link. - Some consider the type declarations unnecessary fluff: link. They don’t practically do anything besides document and throw better errors. This topic often causes heated arguments though.
- A
setupfunction for allocating the arrays would clean up your code, but it isn’t performance necessary.
function setup(n, N)
V = zeros(Float64, n, N)
P = zeros(Float64, n, N)
G = zeros(Float64, n)
return V, P, G
end
function compute!(V, P, G, i)
@. V[:,i] = rand()*(@view P[:,i]) + rand() * G
end
n = 10
N = 100
i = 10
V, P, G = setup(n, N)
compute!(V, P, G, i)
- A custom type
structcould further clean up your code. Though I personally think the previous version is good enough.
struct Parameters
V::Matrix{Float64}
P::Matrix{Float64}
G::Vector{Float64}
end
function setup(n, N)
V = zeros(Float64, n, N)
P = zeros(Float64, n, N)
G = zeros(Float64, n)
return Parameters(V, P, G)
end
function compute!(data, i)
@. data.V[:,i] = rand()*(@view data.P[:,i]) + rand() * data.G
end
n = 10
N = 100
i = 10
data = setup(n, N)
compute!(data, i)
- Typically in Julia, the
functionandstructdefinitions (top half of above code) would be stored in a separate package or file from the function calls (bottom half of above code) for better organization: link. Your original code has function and variable definitions all mixed together which makes it hard to read.