I am trying to run a series of monte carlo simulations. My simulation gives as an output a matrix. I would like to preallocate this matrix for each of the simulations, and also preallocate some work vectors since I am running a series of these simulations.
I’m not too familiar with parallel computing, and looking into it I find myself to be confused about what is the best practise to do this. Initially I thought about using the thread ID to do this, but after some reading it seems to be bad practise(?), and instead I should use channels. But I find it hard to catch the idea behind channels.
Anyways, here is “pseudo code” for my problem, just to illustrate what I’m trying to do.
#ILLUSTRATION
n_simulations = 1000
out = [zeros(2, 2) for _ in 1:n_simulations]
work_vector = zeros(2)
for p in parameters
# here I could do f() = monte_carlo_simulation(p), but due to the preallocation it is more clear not to
for i in 1:n_simulations
monte_carlo_simulation!(p, work_vector, out[i]) # in-place changes to out[i]
end
save_data(out)
end
And what I think I want to do is something like this
#ILLUSTRATION
n_simulations = 1000
out = [zeros(2, 2) for _ in 1:n_simulations]
work_vector = [zeros(2) for _ in 1:Threads.nthreads()]
for p in parameters
Threads.@threads for i in 1:n_simulations
monte_carlo_simulation!(p, work_vector[Threads.myid()], out[i]) # in-place changes to out[i]
end
save_data(out)
end
But I understood that somehow the thread ID can change, and this might not work.
With channels I came up with the idea of storing the work vectors and the preallocated out matrices in channels, and for each simulation taking them out from the channel, using them, and putting them back.
#ILLUSTRATION
n_simulations = 1000
out = Channel{Matrix}(n_simulations)
for _ in 1:n_simulations
put!(out, zeros(2, 2))
end
work_vectors = Channel{Vector}(Threads.nthreads())
for _ in 1:Threads.nthreads()
put!(work_vectors, zeros(2))
end
for p in parameters
@sync for i in 1:n_simulations
Threads.@spawn begin
current_out = take!(out)
work_vector = take!(work_vectors)
monte_carlo_simulation!(p, work_vector, current_out) # in-place changes to out[i]
put!(out, current_out)
put!(work_vectors, work_vector)
end
end
save_data(out)
end
It this how it is supposed to be done? I feel stupid for taking and putting them back in the same channel. Instead of having out as a Channel, should I have it as a list and use out[i], and only use channels with the work vectors? I would be very glad if someone could give me some direction with this, I don’t feel confident with this at all.