Rscript和littler之间的区别

40

除了事实上的 Rscript 是通过 #!/usr/bin/env Rscript 被调用,而 littler 是通过 #!/usr/local/bin/r(在我的系统上)被调用的脚本文件的第一行之外,我发现了执行速度上的某些差异(似乎 littler 较慢一些)。

我创建了两个虚拟脚本,每个脚本运行了1000次,并比较了平均执行时间。

这是 Rscript 文件:

#!/usr/bin/env Rscript

btime <- proc.time()
x <- rnorm(100)
print(x)
print(plot(x))
etime <- proc.time()
tm <- etime - btime
sink(file = "rscript.r.out", append = TRUE)
cat(paste(tm[1:3], collapse = ";"), "\n")
sink()
print(tm)

这里是更小的文件:

#!/usr/local/bin/r

btime <- proc.time()
x <- rnorm(100)
print(x)
print(plot(x))
etime <- proc.time()
tm <- etime - btime
sink(file = "little.r.out", append = TRUE)
cat(paste(tm[1:3], collapse = ";"), "\n")
sink()
print(tm)

你可以看到,它们几乎完全相同(只有第一行和输出文件参数不同)。输出被 sink 到文本文件中,然后使用 read.table 在 R 中导入。我创建了一个 bash 脚本来执行每个脚本 1000 次,然后计算平均值。

这是 bash 脚本:

for i in `seq 1000`
do
./$1
echo "####################"
echo "Iteration #$i"
echo "####################"
done

结果如下:

# littler script
> mean(lit)
    user   system  elapsed 
0.489327 0.035458 0.588647 
> sapply(lit, median)
   L1    L2    L3 
0.490 0.036 0.609 
# Rscript
> mean(rsc)
    user   system  elapsed 
0.219334 0.008042 0.274017 
> sapply(rsc, median)
   R1    R2    R3 
0.220 0.007 0.258 

简而言之:除了明显的执行时间差异,还有其他差异吗?更重要的问题是:为什么应该/不应该选择 littler 而不是 Rscript(或反之亦然)?


1
+1 很棒的问题;喜欢这么详细。 - Shane
谢谢Shane,数据文件在这里:http://bit.ly/ac0Fb1 请注意我的机器非常慢,所以如果你决定运行这些脚本,你更有可能得到较低的值。Dirk像往常一样给出了很好的答案,引起了对这些基准测试脚本的其他问题的关注...所以这些结果要带着一定的保留态度。 - aL3xa
1个回答

25

几个快速评论:

  1. 路径/usr/local/bin/r是任意的,你可以像我们在一些例子中使用/usr/bin/env r。据我回忆,它限制了你可以给r的其他参数,因为只有在通过env调用时才能接受一个参数。

  2. 我不理解你的基准测试以及为什么要这样做。我们在源代码中确实有时间比较,请参见tests/timing.shtests/timing2.sh。也许你想在启动和图形创建之间分开测试或者追求其他目标。

  3. 每当我们运行这些测试时,littler都会获胜。(我现在重新运行它们时,它仍然获胜。)这对我们来说是有道理的,因为如果你查看Rscript.exe的源代码,它通过设置环境和命令字符串来工作,最终调用execv(cmd, av)。littler可以更快地启动。

  4. 主要的代价是可移植性。littler的构建方式使其无法在Windows上运行。或者至少不容易。另一方面,我们已经将RInside移植过来了,所以如果有人真的想要...

  5. littler在2006年9月首次推出,而Rscript是在2007年4月随R 2.5.0一起推出的。

  6. Rscript现在随处可见,这是一个很大的优势。

  7. 在我看来,littler的命令行选项更加合理。

  8. 两者都可以使用CRAN包getopt和optparse进行选项解析。

这是个人偏好。我和别人一起编写了littler,从中学到了很多(例如针对RInside),我仍然认为它很有用——所以我每天都会使用它数十次。它驱动着CRANberries。它也驱动着cran2deb。就像他们说的那样,“你的表现可能因人而异”。

免责声明:littler是我的一个项目。

附言:如果是我来编写测试,我会这样写:

  fun <- function { X <- rnorm(100); print(x); print(plot(x)) }
  replicate(N, system.time( fun )["elapsed"])

或者甚至

  mean( replicate(N, system.time(fun)["elapsed"]), trim=0.05)

为了摆脱异常值。此外,您只需要基本测量I/O(打印和绘图),这两者都可以从R库中获取,因此我预计差异很小。


1
Dirk,感谢您的迅速和详尽的回答!由于您参与了这个项目(是的,在发帖之前我就知道了),所以我非常焦虑地等待着您的回复。附加说明1:我使用ArchLinux,在whereis r中只得到/usr/local/bin/r。如果我输入/usb/bin/env r会出现错误。附加说明2:我会尝试进行测试。我知道littler应该执行得更快,但我仍然惊讶于littler在图形创建方面表现较慢。附加说明3:我不明白,您运行了我的帖子中的脚本,却得到了不同的结果?能否请您发布一下它们? - aL3xa
你本可以给我发电子邮件 :) 关于问题1:这里没有错误,请确保您拥有正确的模式和一切。关于问题2:我的测试是关于每个不同变体启动速度的比较;一旦启动,我期望它们都会执行相同的操作,因为它们都使用相同的基础R。关于问题3:不,我没有使用你的脚本;我只是想表明应该使用system.time(expression)而不是proc.time()结构。 - Dirk Eddelbuettel
1
好的,我会更改虚拟脚本(以作者命名)并查看发生了什么。 - aL3xa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接