为啥矢量化更快
Posted
技术标签:
【中文标题】为啥矢量化更快【英文标题】:Why is vectorization faster为什么矢量化更快 【发布时间】:2013-05-29 23:13:28 【问题描述】:我学习 R 已经有一段时间了,并且遇到了很多关于像我这样的编程类型来矢量化操作的建议。作为一名程序员,我对它为什么/如何更快感兴趣。一个例子:
n = 10^7
# populate with random nos
v=runif(n)
system.time(vv<-v*v; m<-mean(vv)); m
system.time(for(i in 1:length(v)) vv[i]<-v[i]*v[i] ; m<-mean(vv)); m
这给了
user system elapsed
0.04 0.01 0.07
[1] 0.3332091
user system elapsed
36.68 0.02 36.69
[1] 0.3332091
要考虑的最明显的事情是我们正在运行本机代码,即从 C 或 C++ 编译的机器代码,而不是解释代码,这可以从两个示例之间的用户时间的巨大差异(大约 3 个数量级震级)。但还有其他事情发生吗?例如,R 是否:
巧妙的原生数据结构,例如存储稀疏向量或矩阵的巧妙方法,以便我们只在需要时进行乘法运算?
惰性求值,例如在矩阵乘法上,不要在需要时才计算单元格。
并行处理。
别的东西。
为了测试是否可能存在一些稀疏向量优化,我尝试使用不同向量内容进行点积
# populate with random nos
v<-runif(n)
system.time(m<-v%*%v/n); m
# populate with runs of 1 followed by 99 0s
v <-rep(rep(c(1,rep(0,99)),n/100))
system.time(m<-v%*%v/n); m
# populate with 0s
v <-rep(0,n)
system.time(m<-v%*%v/n); m
但是时间上没有显着差异(大约经过 0.09)
(Matlab 的类似问题:Why does vectorized code run faster than for loops in MATLAB?)
【问题讨论】:
【参考方案1】:要考虑的最明显的事情是我们正在运行本机代码, 即从 C 或 C++ 编译的机器代码,而不是解释的 代码
这就是大部分。另一个重要的组件是,由于 R 代码在其设计范式中是函数式的,因此函数(尝试)没有副作用,这意味着在某些(但可能不是全部;R 确实尝试对此保持高效)在 for 循环中调用 [<-
的实例导致必须复制整个对象。 那会变慢。
附注:R 确实具有相当广泛的功能来有效处理sparse 矩阵结构,但它们不是“默认”。
【讨论】:
谢谢,我不太明白你所说的循环中的函数是什么意思,你能提供一个简单的例子或参考吗(我一般对 R 的功能方面很感兴趣从用户的角度影响事物——到目前为止,我所做的一切在风格上都是相当程序化的)。 @TooTonex <- 1:10; tracemem(x); x[5] <- 1
可能是最简单的例子。
这很微妙。我不知道发生了这种情况(有一个discussion thread,它指出 R 主要优化了这些副本,以防其他人想进一步研究)。我做了一些测试,在我的代码中使用for
循环,vv
被复制一次,当i==1
时,但这对性能没有影响。
@TooTone 是的,正如我所提到的,R 确实努力(并且经常成功)最小化这种复制,但是您可以很容易地想象在 for 循环中编写长代码块的更复杂的情况,其中 R无法提前知道一个对象是否需要修改,或者将来是否需要引用,因此复制变得不可避免。
@TooTone 在您的情况下,vv
存在于循环版本之前,因此已经分配了存储空间。每次迭代对*
和[<-
和3 个[
的所有函数调用仍然会产生很大的开销。【参考方案2】:
在这两个示例中,您都在运行解释代码和本机代码。不同之处在于,在第二个中,您在 R 级别执行循环,导致更多的函数调用都需要解释,然后调用 C 代码。在您的第一个示例中,循环发生在已编译的代码中,因此 R 的解释要少得多,R 代码调用要少得多,对已编译代码的调用要少得多。
【讨论】:
【参考方案3】:关于并行处理,开箱即用的 R 不做任何并行处理。当然有内置的parallel
包,但你必须调整你的代码以使用例如mclapply
使用并行处理。有一些选项可以让你的线性代数使用特殊版本的blas
并行计算,但这在 R 中并不标准使用,尽管让它工作似乎并不难。
【讨论】:
谢谢,我想并行处理是 Revolution Analytics R(爱不释手)尝试开展业务的一种方式。以上是关于为啥矢量化更快的主要内容,如果未能解决你的问题,请参考以下文章
有没有办法对这个 pandas 应用方法进行矢量化以使代码运行得更快?