首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么purrr::map2比基本mapply慢?

为什么purrr::map2比基本mapply慢?
EN

Stack Overflow用户
提问于 2018-05-30 15:19:49
回答 1查看 1.1K关注 0票数 3

考虑一下这个简单的基准

代码语言:javascript
复制
list1 <- as.list(rep(1, 50))
list2 <- as.list(rep(1, 50))

microbenchmark::microbenchmark(
+   map2(list1, list2, sum))
Unit: microseconds
                    expr    min       lq     mean   median      uq     max neval
 map2(list1, list2, sum) 375.31 384.2045 481.8708 407.8115 420.641 7923.58   100

microbenchmark::microbenchmark(
+   mapply(sum, X=list1, Y=list2,  SIMPLIFY = FALSE))
Unit: microseconds
                                                expr    min     lq     mean  median      uq    max neval
 mapply(sum, X = list1, Y = list2, SIMPLIFY = FALSE) 46.187 50.634 57.45634 53.3715 59.8715 127.27   100

为什么purrr:map2 mapply慢8倍?我的意思是,我只是在两个列表中并排把数字相加。

问题是我在当前代码中使用的是map2,所以我想了解这里的开销是什么(以及如何修复它)。

谢谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-05-31 11:11:07

正如@eipi10 10在注释中所指出的,当使用更多的数据时,一些函数调用开销就变得不那么重要了:

代码语言:javascript
复制
list1 <- as.list(rep(1, 50000))
list2 <- as.list(rep(1, 50000))
microbenchmark(map2(list1, list2, sum), mapply(sum, X=list1, Y=list2,  SIMPLIFY = FALSE))
Unit: milliseconds
                                                expr      min       lq     mean   median       uq      max neval cld
                             map2(list1, list2, sum) 73.84420 78.21917 82.53853 79.48526 81.28048 218.9266   100   b
 mapply(sum, X = list1, Y = list2, SIMPLIFY = FALSE) 51.92849 54.66514 61.34755 56.99206 58.67459 204.2119   100  a 

mapply使用.Internal,而purr::map2使用.Call访问执行处理的底层C函数。它们的工作方式有一些不同,特别是围绕参数计算,以及R搜索底层代码的方式。

.Internal上的R帮助给出了一个神秘的信息:

.Internal执行对内置到R解释器的内部代码的调用。 只有真正的R向导甚至应该考虑使用这个函数,并且只有R开发人员可以添加到内部函数的列表中。

然而,“R内部手册”解释说:

在构建时编译到R中的C代码可以在所谓的原语中直接调用,也可以通过.Internal接口调用,除了语法之外,它与.External接口非常相似。更准确地说,R维护一个R函数名称表和相应的C函数调用,按照惯例,这些函数都以‘do_’开头,并返回一个SEXP。此表(文件src/main/names.c中的R_FunTab)还指定需要或允许函数的多少参数,函数在调用之前是否要计算参数,以及函数是否是“内部的”,即函数必须通过.Internal接口访问,或者在这种情况下以R作为.Primitive直接访问。

少数原语是特殊的,而不是内置的,也就是说,它们是用未评估的参数输入的。这对于语言结构和赋值操作符,以及有条件地计算其第二个参数的&&和_ ~、.Internal、调用、表达式、缺失、on.exit、引号和替换都是必要的,后者不计算它们的某些参数。

.Call的帮助文件说明:

如果要经常使用这些函数之一,请指定包(将搜索限制在单个DLL上)或将.NAME传递为本机符号对象之一。搜索符号可能需要很长时间,特别是当加载了许多名称空间时。

这意味着在使用.Call时需要花费一些时间搜索DLL中的函数。值得注意的是,purr::map2在使用.Call时没有指定包名,这样做可以减少所需的开销。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50608312

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档