R语言运行在CPU单核单线程上,提高计算效率可以通过并行包:parallel实现,该包属于base包,不需要额外安装。parallel::mclapply
函数是 lapply 的并发版本,可以自定义进程数发挥多CPU核心的优势。“mc” 代表 “多核”,此函数将 lapply 任务分配到多个 CPU 内核创建多线程的形式并发执行。
线程 作为进程的一个执行流,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位,线程的优势是提高应用程序响应;使多CPU系统更加有效。操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上。
NOTE 由于
parallel::mclapply
函数在模式支持方面存在一定的不足,特别是在Windows平台上不适用,因此更推荐使用future
函数包来进行并行计算。参考:R- future.apply 并行包用法简概 - 简书 (jianshu.com)
step.1创建任务环境各种变量
{
library(Seurat);library(dplyr);set.seed(123)
infiles <- dir(path = ".",pattern = "*_raw.rds", full.names = TRUE,recursive = T)
scRNAlist <- lapply(infiles, readRDS) #创建数据集list,用于并行运算,本次测试的scRNAlist包含5个数据对象
rank_i <- bigmemory::big.matrix(1,1,init = 0) #创建共享内存变量,该变量可被所有线程修改,本测试用此变量统计任务完成顺序
m <- synchronicity::boost.mutex() #创建互斥锁,防止共享内存变量被多个线程同时修改引发异常
}
step.2并行运算任务基于parallel::mclapply函数,通过mc.cores = 3
设置同时并发的任务数
parallel::mclapply(scRNAlist,function(e) {#并行迭代数据集list,每次迭代将数据集的元素传递给变量 e
print(paste0(Sys.time()," ",unique(e$orig.ident)," processing>>>")) #任务提交信息
{
suppressWarnings({ #对每个数据集进行降维运算
EC <- e %>% NormalizeData(verbose = F) %>% FindVariableFeatures(verbose = F) %>% ScaleData(verbose = F) %>% RunPCA(verbose = F)
})
synchronicity::lock(m) #进程锁;运行时有且只能有一个运算对共享内存变量进行修改,防止进程间同时修改变量引发异常
rank_i[1] = rank_i[1] + 1 ; #对计序变量进行累加(统计任务完成的顺序)
synchronicity::unlock(m)#解锁,共享内存变量可被修改
}
print(paste0(Sys.time()," ",unique(e$orig.ident)," done!","____________",rank_i[1])) #任务完成提示信息+任务完成顺序
}, mc.cores = 3,mc.preschedule = FALSE) -> tmp ; rm(tmp)
#从任务输出提示信息可以看到,并行循环开始一次性提交了3个任务(3并发),当一个任务完成后,会迅速提交队列的其它任务进行运算饱和计算资源。
#最先提交的A-2-work任务由于数据集最小,最先完成,而最先提交的 A-4-work任务数据集较大,是第三个完成的。
[1] "2022-05-19 20:12:26 A-2-work processing>>>"
[1] "2022-05-19 20:12:26 A-3-work processing>>>"
[1] "2022-05-19 20:12:27 A-4-work processing>>>"
[1] "2022-05-19 20:12:29 A-2-work done!____________1"
[1] "2022-05-19 20:12:29 B-1-work processing>>>"
[1] "2022-05-19 20:12:45 B-1-work done!____________2"
[1] "2022-05-19 20:12:46 B-2-work processing>>>"
[1] "2022-05-19 20:13:00 A-4-work done!____________3"
[1] "2022-05-19 20:13:01 B-3-work processing>>>"
[1] "2022-05-19 20:13:04 A-3-work done!____________4"
[1] "2022-05-19 20:13:08 B-2-work done!____________5"
[1] "2022-05-19 20:13:12 B-3-work done!____________6"