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
. Theconst
approach is intended for actual constants that are fixed across all simulations (none of your variables). It is useful becauseconst
variables are inherently known to all functions and are still fast to use. Link -
You don’t need to allocate
R1
andR2
in your example. Just callrand
directly.
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.
size
is very cheap to compute, so passingn
andN
alongside 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 needn
at 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
setup
function 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
struct
could 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
function
andstruct
definitions (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.