The parallel computing utilizes multiple CPU cores. It is useful when we run many, say more than 100, independent programs, e.g., repetitive simulations or cross-validation. The proper usage of the parallel computing helps us save a great amount of time and speed up the research progress. A more practical way to maximize the efficiency of the parallel computing is to combine it with the high-performance computing (HPC). In this note, I demonstrate how to do the parallel computing on the local machine, followed by its implementation on HPC.

Parallel computing on local machine

Startup

The macOS and Linux users are able to use the function mclapply() from the R package parallel to implement the parallel computing. The Windows users need to use the packages foreach and doParallel, which are easy to learn with the help of documentations. In the following, I demonstrate how to use mclapply() to run 10 replicates simultaneously via a simple example.

First, let us take a look on how many CPU cores are equipped on the computer:

library(parallel)
numCores <- detectCores()
numCores
[1] 4

There are 4 CPU cores on my computer. Next, we wrap up 10 independent replicates by lapply() function. In each replicate, we implement a simple linear regression.

result1 <- lapply(1:1000, function(i){
  x <- matrix(rnorm(1000), 100, 10)
  y <- rnorm(100)
  lm(y~x)
})

Finally, we replace lapply() with mclapply(). The function mclapply() is the same as lapply() except for some additional optional arguments. One commonly used option is mc.cores, which specifies how many CPU cores are used.

result2 <- mclapply(1:1000, function(i){
  x <- matrix(rnorm(1000), 100, 10)
  y <- rnorm(100)
  lm(y~x)
}, mc.cores = numCores)

There is another interesting package called pbmcapply which provides a progress bar. It is useful when the program is time-consuming and you are curious about the progress.

library(pbmcapply)
result3 <- pbmclapply(1:10, function(i){
  x <- matrix(rnorm(1000), 100, 10)
  y <- rnorm(100)
  lm(y~x)
}, mc.cores = numCores)

| | 0%, ETA NA |=============================================================================================== | 80%, ETA 00:00 |===================================================================================================================| 100%, Elapsed 00:00

Reproducibility

The reproducibility of the code is important since it enables other people to reproduce the results appearing on our paper. To achieve the reproducibility of the code in the parallel computing, simply using set.seed() does not work. Instead, we should change the kind of Random Number Generator (RNG) using RNGkind() followed by set.seed().

library(parallel)
RNGkind("L'Ecuyer-CMRG")
set.seed(1)
result4 <- mclapply(1:10, function(i){
  x <- matrix(rnorm(1000), 100, 10)
  y <- rnorm(100)
  lm(y~x)
}, mc.cores = numCores)

Here, we select L'Ecuyer-CMRG type RNG. There are many other types of RNG (see ?RNGkind), but I did not verify if any of them also guarantees the reproducibility of the code in the parallel computing.

Next, we show how to do parallel computing on HPC.

Parallel computing on HPC

Running the parallel computing code on HPC is essentially the same what we did on the local machine. The only difference is that we need to prepare a bash file for submitting the job to the computing nodes on HPC.

We save the preceding code as the R source file simulation.R.

## R source file "simulation.R"
library(parallel)
RNGkind("L'Ecuyer-CMRG")
set.seed(1)
result4 <- mclapply(1:10, function(i){
  x <- matrix(rnorm(1000), 100, 10)
  y <- rnorm(100)
  lm(y~x)
}, mc.cores = numCores)

To submit the file simulation.R to HPC, we need a bash file. Here is an example file, which is named as job.sh.

#!/bin/bash
#SBATCH --job-name="simulation"
#SBATCH -N 1
#SBATCH -n 4
#SBATCH --ntasks-per-core=1
#SBATCH -p genacc_q
#SBATCH --mail-type="END"
#SBATCH --mail-type="FAIL"
#SBATCH -o %x.out
#SBATCH -e %x.err
module load R/3.5.2
Rscript simulation.R

The usage of SBATCH arguments are as follows:

After we log in HPC, we submit the job using in the command line:

sbatch job.sh
LS0tCnRpdGxlOiAiQSBub3RlIG9uIHBhcmFsbGVsIGNvbXB1dGluZyAod2l0aCBSKSIKYXV0aG9yOiBKaW5nIFplbmcKZGF0ZTogU2VwdGVtYmVyIDcsIDIwMjEKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OgogICAgZGZfcHJpbnQ6IHBhZ2VkCi0tLQoKVGhlIHBhcmFsbGVsIGNvbXB1dGluZyB1dGlsaXplcyBtdWx0aXBsZSBDUFUgY29yZXMuIEl0IGlzIHVzZWZ1bCB3aGVuIHdlIHJ1biBtYW55LCBzYXkgbW9yZSB0aGFuIDEwMCwgaW5kZXBlbmRlbnQgcHJvZ3JhbXMsIGUuZy4sIHJlcGV0aXRpdmUgc2ltdWxhdGlvbnMgb3IgY3Jvc3MtdmFsaWRhdGlvbi4gVGhlIHByb3BlciB1c2FnZSBvZiB0aGUgcGFyYWxsZWwgY29tcHV0aW5nIGhlbHBzIHVzIHNhdmUgYSBncmVhdCBhbW91bnQgb2YgdGltZSBhbmQgc3BlZWQgdXAgdGhlIHJlc2VhcmNoIHByb2dyZXNzLiBBIG1vcmUgcHJhY3RpY2FsIHdheSB0byBtYXhpbWl6ZSB0aGUgZWZmaWNpZW5jeSBvZiB0aGUgcGFyYWxsZWwgY29tcHV0aW5nIGlzIHRvIGNvbWJpbmUgaXQgd2l0aCB0aGUgaGlnaC1wZXJmb3JtYW5jZSBjb21wdXRpbmcgKEhQQykuIEluIHRoaXMgbm90ZSwgSSBkZW1vbnN0cmF0ZSBob3cgdG8gZG8gdGhlIHBhcmFsbGVsIGNvbXB1dGluZyBvbiB0aGUgbG9jYWwgbWFjaGluZSwgZm9sbG93ZWQgYnkgaXRzIGltcGxlbWVudGF0aW9uIG9uIEhQQy4KCiMjIFBhcmFsbGVsIGNvbXB1dGluZyBvbiBsb2NhbCBtYWNoaW5lCgojIyMgU3RhcnR1cAoKVGhlIG1hY09TIGFuZCBMaW51eCB1c2VycyBhcmUgYWJsZSB0byB1c2UgdGhlIGZ1bmN0aW9uIGBtY2xhcHBseSgpYCBmcm9tIHRoZSBSIHBhY2thZ2UgKipwYXJhbGxlbCoqIHRvIGltcGxlbWVudCB0aGUgcGFyYWxsZWwgY29tcHV0aW5nLiBUaGUgV2luZG93cyB1c2VycyBuZWVkIHRvIHVzZSB0aGUgcGFja2FnZXMgKipmb3JlYWNoKiogYW5kICoqZG9QYXJhbGxlbCoqLCB3aGljaCBhcmUgZWFzeSB0byBsZWFybiB3aXRoIHRoZSBoZWxwIG9mIGRvY3VtZW50YXRpb25zLiBJbiB0aGUgZm9sbG93aW5nLCBJIGRlbW9uc3RyYXRlIGhvdyB0byB1c2UgYG1jbGFwcGx5KClgIHRvIHJ1biAxMCByZXBsaWNhdGVzIHNpbXVsdGFuZW91c2x5IHZpYSBhIHNpbXBsZSBleGFtcGxlLiAKCkZpcnN0LCBsZXQgdXMgdGFrZSBhIGxvb2sgb24gaG93IG1hbnkgQ1BVIGNvcmVzIGFyZSBlcXVpcHBlZCBvbiB0aGUgY29tcHV0ZXI6CmBgYHtyfQpsaWJyYXJ5KHBhcmFsbGVsKQpudW1Db3JlcyA8LSBkZXRlY3RDb3JlcygpCm51bUNvcmVzCmBgYApUaGVyZSBhcmUgNCBDUFUgY29yZXMgb24gbXkgY29tcHV0ZXIuIE5leHQsIHdlIHdyYXAgdXAgMTAgaW5kZXBlbmRlbnQgcmVwbGljYXRlcyBieSBgbGFwcGx5KClgIGZ1bmN0aW9uLiBJbiBlYWNoIHJlcGxpY2F0ZSwgd2UgaW1wbGVtZW50IGEgc2ltcGxlIGxpbmVhciByZWdyZXNzaW9uLgpgYGB7cn0KcmVzdWx0MSA8LSBsYXBwbHkoMToxMCwgZnVuY3Rpb24oaSl7CiAgeCA8LSBtYXRyaXgocm5vcm0oMTAwMCksIDEwMCwgMTApCiAgeSA8LSBybm9ybSgxMDApCiAgbG0oeX54KQp9KQpgYGAKCkZpbmFsbHksIHdlIHJlcGxhY2UgYGxhcHBseSgpYCB3aXRoIGBtY2xhcHBseSgpYC4gVGhlIGZ1bmN0aW9uIGBtY2xhcHBseSgpYCBpcyB0aGUgc2FtZSBhcyBgbGFwcGx5KClgIGV4Y2VwdCBmb3Igc29tZSBhZGRpdGlvbmFsIG9wdGlvbmFsIGFyZ3VtZW50cy4gT25lIGNvbW1vbmx5IHVzZWQgb3B0aW9uIGlzIGBtYy5jb3Jlc2AsIHdoaWNoIHNwZWNpZmllcyBob3cgbWFueSBDUFUgY29yZXMgYXJlIHVzZWQuCmBgYHtyfQpyZXN1bHQyIDwtIG1jbGFwcGx5KDE6MTAsIGZ1bmN0aW9uKGkpewogIHggPC0gbWF0cml4KHJub3JtKDEwMDApLCAxMDAsIDEwKQogIHkgPC0gcm5vcm0oMTAwKQogIGxtKHl+eCkKfSwgbWMuY29yZXMgPSBudW1Db3JlcykKYGBgCgpUaGVyZSBpcyBhbm90aGVyIGludGVyZXN0aW5nIHBhY2thZ2UgY2FsbGVkICoqcGJtY2FwcGx5Kiogd2hpY2ggcHJvdmlkZXMgYSBwcm9ncmVzcyBiYXIuIEl0IGlzIHVzZWZ1bCB3aGVuIHRoZSBwcm9ncmFtIGlzIHRpbWUtY29uc3VtaW5nIGFuZCB5b3UgYXJlIGN1cmlvdXMgYWJvdXQgdGhlIHByb2dyZXNzLgpgYGB7ciByZXN1bHRzPSdhc2lzJ30KbGlicmFyeShwYm1jYXBwbHkpCnJlc3VsdDMgPC0gcGJtY2xhcHBseSgxOjEwLCBmdW5jdGlvbihpKXsKICB4IDwtIG1hdHJpeChybm9ybSgxMDAwKSwgMTAwLCAxMCkKICB5IDwtIHJub3JtKDEwMCkKICBsbSh5fngpCn0sIG1jLmNvcmVzID0gbnVtQ29yZXMpCmBgYAoKIyMjIFJlcHJvZHVjaWJpbGl0eQpUaGUgcmVwcm9kdWNpYmlsaXR5IG9mIHRoZSBjb2RlIGlzIGltcG9ydGFudCBzaW5jZSBpdCBlbmFibGVzIG90aGVyIHBlb3BsZSB0byByZXByb2R1Y2UgdGhlIHJlc3VsdHMgYXBwZWFyaW5nIG9uIG91ciBwYXBlci4gVG8gYWNoaWV2ZSB0aGUgcmVwcm9kdWNpYmlsaXR5IG9mIHRoZSBjb2RlIGluIHRoZSBwYXJhbGxlbCBjb21wdXRpbmcsIHNpbXBseSB1c2luZyBgc2V0LnNlZWQoKWAgZG9lcyBub3Qgd29yay4gSW5zdGVhZCwgd2Ugc2hvdWxkIGNoYW5nZSB0aGUga2luZCBvZiBSYW5kb20gTnVtYmVyIEdlbmVyYXRvciAoUk5HKSB1c2luZyBgUk5Ha2luZCgpYCBmb2xsb3dlZCBieSBgc2V0LnNlZWQoKWAuCmBgYHtyfQpsaWJyYXJ5KHBhcmFsbGVsKQpSTkdraW5kKCJMJ0VjdXllci1DTVJHIikKc2V0LnNlZWQoMSkKcmVzdWx0NCA8LSBtY2xhcHBseSgxOjEwLCBmdW5jdGlvbihpKXsKICB4IDwtIG1hdHJpeChybm9ybSgxMDAwKSwgMTAwLCAxMCkKICB5IDwtIHJub3JtKDEwMCkKICBsbSh5fngpCn0sIG1jLmNvcmVzID0gbnVtQ29yZXMpCmBgYApIZXJlLCB3ZSBzZWxlY3QgYEwnRWN1eWVyLUNNUkdgIHR5cGUgUk5HLiBUaGVyZSBhcmUgbWFueSBvdGhlciB0eXBlcyBvZiBSTkcgKHNlZSBgP1JOR2tpbmRgKSwgYnV0IEkgZGlkIG5vdCB2ZXJpZnkgaWYgYW55IG9mIHRoZW0gYWxzbyBndWFyYW50ZWVzIHRoZSByZXByb2R1Y2liaWxpdHkgb2YgdGhlIGNvZGUgaW4gdGhlIHBhcmFsbGVsIGNvbXB1dGluZy4KCk5leHQsIHdlIHNob3cgaG93IHRvIGRvIHBhcmFsbGVsIGNvbXB1dGluZyBvbiBIUEMuCgojIyBQYXJhbGxlbCBjb21wdXRpbmcgb24gSFBDCgpSdW5uaW5nIHRoZSBwYXJhbGxlbCBjb21wdXRpbmcgY29kZSBvbiBIUEMgaXMgZXNzZW50aWFsbHkgdGhlIHNhbWUgd2hhdCB3ZSBkaWQgb24gdGhlIGxvY2FsIG1hY2hpbmUuIFRoZSBvbmx5IGRpZmZlcmVuY2UgaXMgdGhhdCB3ZSBuZWVkIHRvIHByZXBhcmUgYSBiYXNoIGZpbGUgZm9yIHN1Ym1pdHRpbmcgdGhlIGpvYiB0byB0aGUgY29tcHV0aW5nIG5vZGVzIG9uIEhQQy4KCldlIHNhdmUgdGhlIHByZWNlZGluZyBjb2RlIGFzIHRoZSBSIHNvdXJjZSBmaWxlICpzaW11bGF0aW9uLlIqLgpgYGB7cn0KIyBSIHNvdXJjZSBmaWxlICJzaW11bGF0aW9uLlIiCmxpYnJhcnkocGFyYWxsZWwpClJOR2tpbmQoIkwnRWN1eWVyLUNNUkciKQpzZXQuc2VlZCgxKQpyZXN1bHQ0IDwtIG1jbGFwcGx5KDE6MTAsIGZ1bmN0aW9uKGkpewogIHggPC0gbWF0cml4KHJub3JtKDEwMDApLCAxMDAsIDEwKQogIHkgPC0gcm5vcm0oMTAwKQogIGxtKHl+eCkKfSwgbWMuY29yZXMgPSBudW1Db3JlcykKYGBgCgpUbyBzdWJtaXQgdGhlIGZpbGUgKnNpbXVsYXRpb24uUiogdG8gSFBDLCB3ZSBuZWVkIGEgYmFzaCBmaWxlLiBIZXJlIGlzIGFuIGV4YW1wbGUgZmlsZSwgd2hpY2ggaXMgbmFtZWQgYXMgKmpvYi5zaCouCmBgYAojIS9iaW4vYmFzaAojU0JBVENIIC0tam9iLW5hbWU9InNpbXVsYXRpb24iCiNTQkFUQ0ggLU4gMQojU0JBVENIIC1uIDQKI1NCQVRDSCAtLW50YXNrcy1wZXItY29yZT0xCiNTQkFUQ0ggLXAgZ2VuYWNjX3EKI1NCQVRDSCAtLW1haWwtdHlwZT0iRU5EIgojU0JBVENIIC0tbWFpbC10eXBlPSJGQUlMIgojU0JBVENIIC1vICV4Lm91dAojU0JBVENIIC1lICV4LmVycgptb2R1bGUgbG9hZCBSLzMuNS4yClJzY3JpcHQgc2ltdWxhdGlvbi5SCmBgYAoKVGhlIHVzYWdlIG9mIFNCQVRDSCBhcmd1bWVudHMgYXJlIGFzIGZvbGxvd3M6CgotICpOKjogdGhlIG51bWJlciBvZiBub2Rlcy4gSSBwcmVmZXIgdG8ga2VlcCBpdCBhcyAxLgotICpuKjogdGhlIG51bWJlciBvZiBDUFUgY29yZXMuIEkgc3VnZ2VzdCB0byBzZXQgaXQgYXMgNCBvciA4IChvciBhcyBsYXJnZSBhcyAxNiBpZiB0aGUgY29tcHV0aW5nIHJlc291cmNlcyBhcmUgYXZhaWxhYmxlKS4gSXQgdGFrZXMgbXVjaCB0aW1lIHRvIHdhaXQgZm9yIHRoZSBhbGxvY2F0aW9uIG9mIHRvbyBtYW55IGNvcmVzLgotICpudGFza3MtcGVyLWNvcmUqOiB0aGUgbnVtYmVyIG9mIHRhc2sgb24gZWFjaCBjb3JlLgotICpwKjogdGhlIEhQQyBwYXJ0aXRpb24uIFVzZSBwYXJ0aXRpb24gKmdlbmFjY19xKiBpZiB0aGUgam9iIGlzIHRpbWUtY29uc3VtaW5nLCBidXQgdGhpcyBwYXJ0aXRpb24gaXMgY3Jvd2RlZC4gSWYgdGhlIGpvYiBjYW4gZmluaXNoIHdpdGhpbiA0IGhvdXJzLCB0aGVuIHVzZSBwYXJ0aXRpb25zICpiYWNrZmlsbCogYW5kICpiYWNrZmlsbDIqLgotICpvLCBlKjogc3BlY2lmeSB0aGUgbmFtZXMgb2Ygb3V0cHV0IGFuZCBlcnJvciBmaWxlcy4gJXggcmVwcmVzZW50cyB0aGUgYGpvYi1uYW1lYC4gVGhlcmVmb3JlLCB0aGUgam9iIHdpbGwgZ2l2ZSB0aGUgb3V0cHV0IGZpbGUgKnNpbXVsYXRpb24ub3V0KiBhbmQgdGhlIGVycm9yIGZpbGUgKnNpbXVsYXRpb24uZXJyKi4KCkFmdGVyIHdlIGxvZyBpbiBIUEMsIHdlIHN1Ym1pdCB0aGUgam9iIHVzaW5nIGluIHRoZSBjb21tYW5kIGxpbmU6CmBgYApzYmF0Y2ggam9iLnNoCmBgYAoKCgoK