Department of Mathematics
University of Manitoba*
Some of the computational tasks we perform are embarrassingly parallel: they can be split into independent sub-tasks that can be run in parallel
For example, independent simulations of a stochastic process or evaluation of the output of a function at different parameter values
These problems are easy to parallelise
\[ S_{\text{latency}}(s)= \frac {1}{(1-p)+p/s} \]
where - \(S_{\text{latency}}\) is the theoretical speedup of the execution of the whole task - \(s\) is the speedup of the part of the task that benefits from improved system resources - \(p\) is the proportion of execution time that the part benefiting from improved resources originally occupied
R
uses the word cores even when referring to threadsThis is probably the most confusing part about parallel computing (until you think about it)
Workers are separated R
instances which receive their work orders from the main R
instance (the dispatcher), so they must be given all the information needed to carry out the work
This needs to be done prior to the computation, as workers receive minimal information from the dispatcher at runtime…
parallel
detectCores()
We take the value of \(\mathcal{R}_0\) in an SIR model with demography and proportional (standard) incidence \[ \mathcal{R}_0 = \frac{\beta}{d+\gamma} \] We want to know how the value of \(\mathcal{R}_0\) changes as a function of changes in the parameters \(\beta,\gamma,d\)
This is sensitivity analysis and will be covered in detail in another Vignette
We define the function whose value we want to compute
We create a “wrapper” of the function R0
In more complex problems, this wrapper function is really important and can be much more evolved.. It can also take other parameters held constant
We use the sensitivity
library to generate sample values of the parameters. The function parameterSets
takes a list with minimum and maximum values for each parameter and a number of samples to generate, so we first make the list
# Detect number of cores, use all but 1
no_cores <- parallel::detectCores() - 1
# Initiate cluster
tictoc::tic("whole parallel phase")
cl <- parallel::makeCluster(no_cores)
# Export needed variables
parallel::clusterExport(cl,
c("R0",
"one_run_R0"))
# Run computation
tictoc::tic("parLapply")
result = parallel::parLapply(cl = cl, X = pars.sobol,
fun = one_run_R0)
tictoc::toc()
# Stop cluster
parallel::stopCluster(cl)
tictoc::toc()
nb_sims = 1000
sequential: 0.015 sec elapsed
parLapply: 0.096 sec elapsed
cluster: 1.125 sec elapsed
nb_sims = 10000
sequential: 0.093 sec elapsed
parLapply: 0.114 sec elapsed
cluster: 1.034 sec elapsed
nb_sims = 1e+05
sequential: 0.878 sec elapsed
parLapply: 0.506 sec elapsed
cluster: 1.416 sec elapsed
nb_sims = 1e+06
sequential: 15.807 sec elapsed
parLapply: 14.833 sec elapsed
cluster: 16.881 sec elapsed