Performance 将JIT与R结合使用可能存在的缺点?

Performance 将JIT与R结合使用可能存在的缺点?,performance,r,compiler-construction,jit,Performance,R,Compiler Construction,Jit,我最近发现,可以使用编译器包将JIT(即时)编译与R结合使用(我在中总结了我在本主题中的发现) 我被问到的一个问题是: 有什么陷阱吗?听起来太好了,不可能是真的,只要写一行就行了 这就是代码 环顾四周后,我发现一个可能的问题与JIT的“启动”时间有关。但是,在使用JIT时,还有其他问题需要注意吗 我想R的环境架构会有一些限制,但我想不出一个简单的例子来说明这个问题,任何建议或危险信号都会有很大帮助?使用rpart的简单测试的输出可能是一个建议,在所有情况下都不要使用enableJIT: libr

我最近发现,可以使用编译器包将JIT(即时)编译与R结合使用(我在中总结了我在本主题中的发现)

我被问到的一个问题是:

有什么陷阱吗?听起来太好了,不可能是真的,只要写一行就行了 这就是代码

环顾四周后,我发现一个可能的问题与JIT的“启动”时间有关。但是,在使用JIT时,还有其他问题需要注意吗


我想R的环境架构会有一些限制,但我想不出一个简单的例子来说明这个问题,任何建议或危险信号都会有很大帮助?

使用rpart的简单测试的输出可能是一个建议,在所有情况下都不要使用enableJIT:

library(rpart)
fo <- function() for(i in 1:500){rpart(Kyphosis ~ Age + Number + Start, data=kyphosis)}
system.time(fo())
#User      System verstrichen 
#2.11        0.00        2.11 

require(compiler)
enableJIT(3)
system.time(fo())
#User      System verstrichen 
#35.46        0.00       35.60
库(rpart)

fo在前面的答案的基础上,实验表明问题不在于循环的编译,而在于闭包的编译。[enableJIT(0)或enableJIT(1)使代码保持快速,enableJIT(2)使代码速度显著降低,enableJIT(3)比上一个选项略快(但仍然非常慢)]。同样与Hansi的评论相反,cmpfun的执行速度也达到了类似的程度。

上面给出的
rpart
示例似乎不再是一个问题:

library("rpart")
fo = function() {
  for(i in 1:500){
    rpart(Kyphosis ~ Age + Number + Start, data=kyphosis)
  }
}    system.time(fo())
#   user  system elapsed 
#  1.212   0.000   1.206 
compiler::enableJIT(3)
# [1] 3
system.time(fo())
#   user  system elapsed 
#  1.212   0.000   1.210 
我还尝试了其他一些例子,比如

  • 培养一个载体
  • 一个函数,它只是
    mean
虽然我并不总是能得到加速,但我从未经历过明显的减速



原则上,一旦编译并加载了字节码,它的解释速度应始终至少与原始AST解释器一样快。一些代码会从大的加速中受益,这通常是包含大量标量操作和循环的代码,其中大部分时间都花在R解释上(我见过加速10倍的示例,但任意的微基准确实可以根据需要放大)。有些代码将以相同的速度运行,这通常是经过良好矢量化的代码,因此几乎不需要花费时间进行解释。现在,编译本身可能很慢。因此,即时编译器现在在猜测不会有回报时不会编译函数(启发式随着时间的推移而改变,这已经在3.4.x中)。启发式算法并不总是猜测正确,因此可能存在编译无法获得回报的情况。典型的问题模式是代码生成、代码修改和对闭包中捕获的环境绑定的操作

包可以在安装时进行字节编译,这样编译成本就不会在运行时(重复)支付,至少对于提前知道的代码是这样。这是R开发版本中的默认值。虽然编译代码的加载速度比编译要快得多,但在某些情况下,可能会加载甚至不会执行的代码,因此实际上可能会有开销,但总体预编译是有益的。最近,已经对GC的一些参数进行了调整,以降低加载不会执行的代码的成本


我对包编写器的建议是使用默认值(在发布版本中,即时编译现在默认为打开,在开发版本中,在包安装时字节编译现在为打开)。如果您发现一个字节码编译器性能不好的示例,请提交一份bug报告(我还看到了一个案例,涉及早期版本中的
rpart
)。我建议不要进行代码生成和代码操作,尤其是在热循环中。这包括在闭包捕获的环境中定义闭包、删除和插入绑定。显然,不应该在热循环中执行
eval(解析(text=
)(如果没有字节编译,这已经很糟糕了)。使用分支总比动态生成新闭包(没有分支)要好。另外,使用循环编写代码比使用大型表达式(没有循环)动态生成代码要好.现在使用字节码编译器,在R中编写在标量上运行的循环通常是可以的(性能不会像以前那么差,因此在性能关键部分可以更经常地不切换到C)。

我不确定性能是否会受到影响(除了初始编译(可能会增加内存使用量))但是“注意:没有可见的绑定”消息通常会让新手感到不知所措(例如,如果使用ggplot2),并且会导致tab complete(至少对我来说是这样)你好,mweylandt。你知道错误信息是什么意思吗?在创建新版本时,我一直在我的包的描述文件中放入
ByteCompile:true
,它似乎工作正常。我做了一个小测试
http://www.johnmyleswhite.com/notebook/2012/03/31/julia-i-love-you/comment-page-1/#comment-19522
和编译版本,
fib2c
比普通版本运行快4倍,
fib2a
。在某些情况下,即使不进行字节编译,R也已经很快了(例如,使用C的高度矢量化代码)在这些情况下,显然没有什么加速的机会——它主要对较慢的R代码有用。另一种方法是在加载函数时只编译函数,例如,你的私有库等。我注意到一些类似的东西,但目的不同:嗨,Dirk,我知道(甚至在帖子中提到过)。这是否意味着使用JIT在任何情况下都没有坏处?!这很奇怪,因此在fo中通过bye编译循环会引起问题。如果您正常编译它,则不会发生这种情况。请注意,rpart已经进行了字节编译。编译需要很长的半分钟:我看到了相同的情况(2.8 s-42.6 s),但随后执行system.time(fo())同样只需要2.6秒。我相信,rpart调用C/Fortran。这是对R的JIT能力的一个很好的测试吗?不是更好吗
R> sessionInfo()
R version 3.3.0 (2016-05-03)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 16.04 LTS