R语言 并行编程
并行编程是一种软件开发实践,它涉及到将一个计算或任务划分为较小的部分,可以同时或并行执行。并行编程可以通过利用计算机或集群中的多个处理器或核心,帮助提高R代码的性能和效率。并行编程的主要概念是,如果使用一个处理器可以在S秒内完成一个操作,那么当有N个处理器参与时,它应该能够在S/N秒内执行。
在R中进行并行编程的必要性
大多数时候,R的代码只在单核上快速工作。但有时操作会-
- 消耗太多的CPU时间。
-
占用过多的内存空间。
-
从磁盘中读出或写入磁盘时消耗了太多时间。
-
转移需要花费大量时间。
隐性的平行关系
R为我们提供了强大的库支持。有时,我们甚至在不知情的情况下进行并行编程。这是因为现在的R提供了这样的库,提供了内置的并行性,我们可以在后台使用它们。这样一种隐藏的并行性提高了我们的编程效率。但如果能知道实际发生了什么(甚至在幕后),那就更好了。
让我们考虑一个隐藏并行的例子
并行 BLAS
基本线性代数子程序(BLAS)库是在R中为特定类型的CPU定制的,以便从芯片组的结构中获益。拥有一个优化的BLAS总是有益的,因为它提高了执行的性能。
尴尬的平行主义
尴尬的并行性是统计学和数据科学中的一种常见方法。它能够解决数据科学和统计学中的许多问题。在这种类型的并行中,问题被划分为多个独立的部分,所有的部分都是同时执行的,因为它们之间没有任何联系。
语法
在R中,使用lapply()函数可以实现令人尴尬的并行化。这个函数的语法如下 –
lapply(list, function)
示例
它接受一个列表和一个函数。它返回一个长度等于输入列表的列表。
# Creating a list
myList <- list(data1 = 1:5, data2 = 10:15)
# Use lapply() function and
# calculate the mean
lapply(myList, mean)
输出
$data1
[1] 3
$data2
[1] 12.5
正如你在输出中所看到的,列表元素的平均值已经显示出来了。
lapply()函数的工作原理类似于loop-it循环,我们遍历列表中的每个元素并对其应用函数。
现在让我们更深入地了解实际发生的情况——。
我们一个一个地迭代每个元素,这就是为什么当我们对列表中的单个元素应用函数时,其他元素只是在内存中闲置。我们可以在R中并行化这件事。主要的想法是划分列表对象,并把它们放到多个处理器中,然后我们可以同时对列表的所有子集应用该函数。
- 将清单分成多个处理器。
-
将提供的函数克隆到多个处理器中。
-
将该功能同时应用于多个核心。
-
将来自多个核心的结果合并为一个单一的列表。
-
显示结果。
R中的并行编程包
R中的并行包随R的安装而来。这个包是两个包的组合:R中的雪和多核。
并行包是专门用来将任务以并行的方式交付给每个内核的。具体来说,它是由mclapply()函数进行的。mclapply()函数类似于lapply,但前者能够将任务分配给多个处理器。mclapply()函数还收集了函数调用的结果,将其合并,并将结果作为一个列表返回,其长度与原始列表相同。请注意,R允许我们使用detectCores()函数来获得系统中存在的内核数量。
让我们考虑以下程序,说明mclapply()函数的工作情况 –
注意 – 请注意,”mc.cores “的值大于1只在非窗口操作系统中工作。所以,下面的代码是在windows以外的操作系统中执行的。
示例
# Import library
library(parallel)
library(MASS)
# Creating a list
myList <- list(data1 = 1:10000000, data2 = 1:100000000)
cat("The estimated time using lapply() function:
")
# Calculate the time taken using lapply
system.time(
results <- lapply(myList, mean)
)
# Get the number of cores
numberOfCores <- detectCores()
cat("The estimated time using clapply() function:
")
# Calculate the time taken using lapply() using mclapply()
system.time(
results <- mclapply(myList, mean, mc.cores = numberOfCores)
)
输出
The estimated time using lapply() function:
user system elapsed
0.40 0.00 0.43
The estimated time using clapply() function:
user system elapsed
0.12 0.00 0.17
你可以在输出中看到使用apply()和mcapply()函数时的时间差异。
使用foreach和doParallel包进行并行编程
现在,我们将看到如何使用R中的foreach库来实现并行编程。
示例
# Iterate using the for loop from 1 to 5
# And print the square of each number
for (data in 1:5) {
print(data * data)
}
输出
[1] 1
[1] 4
[1] 9
[1] 16
[1] 25
正如你在输出中看到的,从1到5的每个数字的平方显示在控制台。
Foreach包
现在让我们来谈谈foreach包和方法。foreach包为我们提供了foreach()方法,使用它我们可以很容易地实现并行编程。
语法
如果你的系统中还没有安装foreach库,那么在CRAN的终端使用以下命令–
install.packages("foreach")
foreach方法类似于基本的for循环方法,但前者使用%do%操作符,这意味着运行一个特定类型的表达式。两者在返回数据结构方面也有区别。
示例
请看下面的程序,它说明了foreach方法的工作原理——。
# Import foreach library
library(foreach)
# Iterate using the foreach loop from 1 to 5
# And print the square of each number
foreach (data=1:5) %do% {
data * data
}
输出
[[1]]
[1] 1
[[2]]
[1] 4
[[3]]
[1] 9
[[4]]
[1] 16
[[5]]
[1] 25
正如你在输出中看到的,从1到5的每个数字的平方显示在控制台。
doParallel包
doParallel包为我们提供了%dopar%操作符,我们可以把它和foreach一起使用。通过与foreach一起使用这个操作符,我们将能够在每次迭代中使用不同的处理核心。你可以使用CRAN中的以下命令下载 “doParallel “包———-。
install.packages("doParallel")
示例
现在让我们看看下面的程序,它演示了foreach方法和%dopar%操作符的工作。
# Import foreach library
library(foreach)
library(doParallel)
library(MASS)
# Get the total number of cores
numOfCores <- detectCores()
# Register all the cores
registerDoParallel(numberOfCores)
# Iterate using the for loop from 1 to 5
# And print the square of each number
# Using parallelism
foreach (data=1:5) %dopar% {
print(data * data)
}
输出
[[1]]
[1] 1
[[2]]
[1] 4
[[3]]
[1] 9
[[4]]
[1] 16
[[5]]
[1] 25
从1到5的每个数字的平方都显示在控制台。
结论
在本教程中,我们讨论了R语言中的并行编程。我们谈到了foreach和doParallel等库,使用这些库可以在R语言中实现并行编程。我们还看到了mcapply()等函数的工作。平行编程是任何编程语言中最重要的概念之一,我相信本教程肯定有助于在数据科学领域获得良好的知识。