为啥矢量化更快

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 循环中调用 [&lt;- 的实例导致必须复制整个对象。 会变慢。

附注:R 确实具有相当广泛的功能来有效处理sparse 矩阵结构,但它们不是“默认”。

【讨论】:

谢谢,我不太明白你所说的循环中的函数是什么意思,你能提供一个简单的例子或参考吗(我一般对 R 的功能方面很感兴趣从用户的角度影响事物——到目前为止,我所做的一切在风格上都是相当程序化的)。 @TooTone x &lt;- 1:10; tracemem(x); x[5] &lt;- 1 可能是最简单的例子。 这很微妙。我不知道发生了这种情况(有一个discussion thread,它指出 R 主要优化了这些副本,以防其他人想进一步研究)。我做了一些测试,在我的代码中使用for 循环,vv 被复制一次,当i==1 时,但这对性能没有影响。 @TooTone 是的,正如我所提到的,R 确实努力(并且经常成功)最小化这种复制,但是您可以很容易地想象在 for 循环中编写长代码块的更复杂的情况,其中 R无法提前知道一个对象是否需要修改,或者将来是否需要引用,因此复制变得不可避免。 @TooTone 在您的情况下,vv 存在于循环版本之前,因此已经分配了存储空间。每次迭代对*[&lt;- 和3 个[ 的所有函数调用仍然会产生很大的开销。【参考方案2】:

在这两个示例中,您都在运行解释代码和本机代码。不同之处在于,在第二个中,您在 R 级别执行循环,导致更多的函数调用都需要解释,然后调用 C 代码。在您的第一个示例中,循环发生在已编译的代码中,因此 R 的解释要少得多,R 代码调用要少得多,对已编译代码的调用要少得多。

【讨论】:

【参考方案3】:

关于并行处理,开箱即用的 R 不做任何并行处理。当然有内置的parallel 包,但你必须调整你的代码以使用例如mclapply 使用并行处理。有一些选项可以让你的线性代数使用特殊版本的blas 并行计算,但这在 R 中并不标准使用,尽管让它工作似乎并不难。

【讨论】:

谢谢,我想并行处理是 Revolution Analytics R(爱不释手)尝试开展业务的一种方式。

以上是关于为啥矢量化更快的主要内容,如果未能解决你的问题,请参考以下文章

更快的 sklearn tf-idf 矢量化器

矢量访问速度,哪种方法更快?

有没有办法对这个 pandas 应用方法进行矢量化以使代码运行得更快?

将时间戳数据与另一个数据集中的最接近时间相匹配。正确矢量化?更快的方式?

为啥库需要硬编码矢量化而不是编译器自动矢量化

ARCGIS矢量数据批量合库为啥会失败