高性能计算

栏目: 编程工具 · 发布时间: 7年前

内容简介:《R语言编程指南》

《R语言编程指南》

代码性能

简单看函数运行时间,用 system.time() 函数。

高级点,使用 microbenchmark 包的 microbenchmark() 函数。

例如:

library(microbenchmark)
x = rnorm(10000)
microbenchmark(x)
#> Unit: nanoseconds
#>  expr min lq mean median uq  max neval
#>     x  30 31 47.6     32 32 1561   100

给出了类似 summary() 函数结果的样子,默认计算100次。

代码性能分析

R提供了内置函数 Rprof() 对代码性能进行分析。

使用方法:调用Rprof()开始分析,运行想分析的代码,然后调用Rprof(NULL)停止分析,最后调用summaryRprof()查看分析结果:

x = rnorm(10000)
tmp = tempfile(fileext = ".out")
Rprof(tmp)
for (i in 1:1000) {
    cumsum(x)
}
Rprof(NULL)

summaryRprof(tmp)
#> $by.self
#>          self.time self.pct total.time total.pct
#> "cumsum"      0.06      100       0.06       100
#> 
#> $by.total
#>                       total.time total.pct self.time self.pct
#> "cumsum"                    0.06       100      0.06      100
#> "block_exec"                0.06       100      0.00        0
#> "call_block"                0.06       100      0.00        0
#> "eval.parent"               0.06       100      0.00        0
#> "eval"                      0.06       100      0.00        0
#> "evaluate_call"             0.06       100      0.00        0
#> "evaluate::evaluate"        0.06       100      0.00        0
#> "evaluate"                  0.06       100      0.00        0
#> "handle"                    0.06       100      0.00        0
#> "in_dir"                    0.06       100      0.00        0
#> "knitr::knit"               0.06       100      0.00        0
#> "local"                     0.06       100      0.00        0
#> "process_file"              0.06       100      0.00        0
#> "process_group.block"       0.06       100      0.00        0
#> "process_group"             0.06       100      0.00        0
#> "rmarkdown::render"         0.06       100      0.00        0
#> "timing_fn"                 0.06       100      0.00        0
#> "withCallingHandlers"       0.06       100      0.00        0
#> "withVisible"               0.06       100      0.00        0
#> 
#> $sample.interval
#> [1] 0.02
#> 
#> $sampling.time
#> [1] 0.06

Rprof() 设定 line.profiling = TRUE 时,将改为分析代码行,而不是函数,这有利于分析复杂的计算过程。

高级点,使用RStudio提供的 profvis() ,它是一个交互式可视化的工具。

install.packages("profvis")

提供代码性能

cmpfun()

前两点不细讲了。

使用字节码编译器

如果不是R内置的函数,一般通过字节码进行编译后再使用会提升速度,这里说下流程:

#载入包
library(compiler)

#调用函数进行编译
# 假设我们写了一个自定义的sum函数
sum_cmp = cmpfun(sum)

# 然后再使用sum_cmp函数

使用并行计算

由于不同的操作系统有不同的线程和线程模型的实现,因此某些功能在 Linux 和MacOS系统与Windows系统不同。

我们先创建一个伪任务,以方便进行并行计算:

simulate = function(x) {
    s = 0
    for (i in x){
        while(i >= 1){
            s = i * (i - 1)
            i = i - 1
        }
    }
    s
}
system.time(simulate(1:11000))
#>  用户  系统  流逝 
#> 7.052 0.023 7.087

在Windows下使用

Windows下需要先创建多个R会话的本地集群:

library(parallel)
cl = makeCluster(detectCores())

detectCores() 返回我们计算机有的CPU核数目,然后调用 parLapply() 函数,它是并行版本的 lapply() 函数:

system.time(parLapply(cl, 1:11000, simulate))
#>  用户  系统  流逝 
#> 0.008 0.001 4.038

当我们不需要这个集群时,调用 stopCluster() 终止刚才创建的R会话。

注意,当我们使用这种方式进行并行计算时,创建了新的R会话,因此环境里没有用户定义的变量。如果有我们自己的数据,需要提前导入。

使用 clusterExport() 可以将数据导入到集群,使用 clusterEvalQ() 可以在每个集群节点上计算表达式。

或者使用 clusterCall()<<- 在每个节点创建全局变量,而 <- 创建局部变量。

stopCluster()
#> Error in defaultCluster(cl): no cluster 'cl' supplied and none is registered

Linux和MacOS使用并行计算

在这两个系统上使用并行计算要比Windows容易的多, mclapply() 可直接将当期R会话分配到多个会话中,保留所有内容,并为每个子会话安排任务,并行运行:

system.time( mclapply(1:1100, simulate, mc.cores = detectCores()))
#>  用户  系统  流逝 
#> 0.135 0.048 0.073

我们无需导出变量到集群中,因为在每个分配的进程中,它们是可以直接使用的。

我们还可以用非常灵活的方式创建并行作业,例如创建一个生成10个随机数的作业:

job1 = mcparallel(rnorm(10), "job1")

然后调用 mccollect() 函数收集作业结果:

mccollect(job1)
#> $`3979`
#>  [1] -0.0816  0.6930 -0.8022 -1.6354 -1.0508 -0.7526 -1.6807 -1.9063
#>  [9] -2.2072 -0.1354

还可以通过编程创建并运行多项作业,例如我们创建8项作业,每个随机休眠一段时间:

jobs = lapply(1:8, function(i){
    mcparallel({
        t = rbinom(1, 5, 0.6)
        Sys.sleep(t)
        t
    }, paste0("job", i))
    
})

system.time(res <- mccollect(jobs))
#>  用户  系统  流逝 
#> 0.018 0.023 3.921

使用Rcpp

并行计算只有在每次迭代都是独立的情况下才可行,这样最终结果才不会依赖运行顺序,然后并非所有的任务都像这样理想。另一种让算法更快的方式是使用Rcpp( http://www.rcpp.org )。

Rcpp是一个扩展包,它使我们能够利用R和C++的无缝整合来编写C++代码。使用Rcpp可以编写C++代码,并且代码中还可以调用R函数,利用R数据结构的优势。

使用Rcpp,先要使用正确的 工具 链,在Windows系统下使用Rtools,在Linux和MacOS下也需要安装正确的C/C++工具链。

然后我们就安装 Rcpp 包:

install.packages("Rcpp")

先在Rcpp目录下创建一个C++源文件:

#include <Rcpp.h>
usingnamespace Rcpp;

// [[Rcpp::export]]
NumericVector timesTwo (NumericVector x){
    return x * 2;
}

如果你不熟悉C++语法,可以通过 http://www.learncpp.com 学习最简单的部分。

C++是强类型语言,需要指定函数参数的类型和函数返回的类型。使用[[Rcpp::export]]注释的函数会被Rcpp捕获,当在RStudio中执行一个脚本文件,或者直接使用Rcpp::sourceCpp,这些C++函数将被自动编译并移植到R的工作环境中。

Rcpp::sourceCpp("../../R/Rcpp/rcpp-demo.cpp")
#> 
#> > timesTwo(42)
#> [1] 84
timesTwo
#> function (x) 
#> .Call(<pointer: 0x112cb3620>, x)

Rcpp官网: http://www.rcpp.org/

一些相关技术与包:

  • OpenMP
  • RcppParallel

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Head First jQuery

Head First jQuery

Ryan Benedetti , Ronan Cranley / O'Reilly Media / 2011-9 / USD 39.99

Want to add more interactivity and polish to your websites? Discover how jQuery can help you build complex scripting functionality in just a few lines of code. With Head First jQuery, you'll quickly g......一起来看看 《Head First jQuery》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具