与基础mapply相比,为什么purrr :: map2这么慢?

时间:2018-05-30 15:19:49

标签: r list lapply purrr

考虑这个简单的基准

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几乎map2慢<8> }?我的意思是,我只是简单地在两个列表中并排数字。

问题是我在当前代码中使用for(int i=0;i<8;i++){ for(int j=0;j<8;j++){ //grid08(8X8) Pane p=new Pane(); ImageView im=new ImageView(); Label l=new Label(""); im.fitWidthProperty().bind(p.widthProperty()); im.fitHeightProperty().bind(p.heightProperty()); l.prefWidthProperty().bind(p.widthProperty()); l.prefHeightProperty().bind(p.heightProperty()); p.getChildren().addAll(im,l); l.setVisible(false); l.setStyle("-fx-text-fill: #fff; -fx-font-size: 12px"); l.setAlignment(Pos.CENTER); p.setStyle("-fx-background-color: black;"); grid.add(p,j,i);//grid->instance of gridPane p.setOnDragOver(new EventHandler<DragEvent>() { @Override public void handle(DragEvent event) { if(!l.isVisible()){ event.acceptTransferModes(TransferMode.ANY); } } }); p.setOnDragDropped(new EventHandler<DragEvent>() { @Override public void handle(DragEvent event) { play(im,event.getDragboard().getString()); } }); } } play(ImageView im,String Url){ new Thread(new Runnable(){ frameGrabber = new FFmpegFrameGrabber(Url); frameGrabber.setVideoOption("preset","ultrafast"); frameGrabber.setOption("rtsp_transport","tcp"); frameGrabber.setOption("stimeout" , "60000"); frameGrabber.setAudioChannels(0); frameGrabber.setAudioCodec(0); try { frameGrabber.start(); start=true; } catch (Exception e) { } JavaFXFrameConverter jconverter=new JavaFXFrameConverter(); while(true){ Frame frame = frameGrabber.grabImage(); Image image=jconverter.convert(frame); Platform.runlater(new Runnable(){ im.setImage(image); }); } }).start(); } ,所以我想了解这里的开销是什么(以及如何修复它)

谢谢!

1 个答案:

答案 0 :(得分:3)

正如评论中提到的@ eipi10,当使用大量数据时,有一些函数调用开销变得不那么重要了:

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使用.Internalpurr::map2使用.Call来访问执行处理的基础C函数。它们的工作方式存在一些差异,特别是在参数评估方面,以及R搜索底层代码的方式。

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

  

.Internal执行对内置代码的调用   R翻译。

     

只有真正的R向导才应该考虑使用此功能   R开发人员可以添加到内部函数列表中。

然而,R Internals手册解释了:

  

在构建时编译成R的C代码可以直接调用什么   被称为基元或通过.Internal接口,这是非常的   类似于.External接口,语法除外。更确切地说,R   维护一个R函数名和相应的C函数表   按照惯例,调用都以'do_'开头并返回SEXP。这个   table(文件src / main / names.c中的R_FunTab)也指定了多少   无论是否需要函数的参数都是必需的或允许的   在调用之前要对参数进行求值,以及是否对函数进行求值   是'内部',因为它必须通过.Internal访问   接口,或直接可访问,在这种情况下,它在R中打印为   .Primitive。

  

少数基元是特殊的而不是内置的   他们是以未经评估的论点进入的。这很清楚   语言结构和赋值运算符所必需的   以及&amp;&amp;和||有条件地评估他们的第二个   参数,和〜,。内部,调用,表达,缺失,on.exit,引用   并且替代哪些不评估他们的一些论点。

.Call笔记的帮助文件:

  

如果要经常使用其中一个功能,请指定PACKAGE   (将搜索限制在单个DLL中)或将.NAME作为其中一个传递   原生符号对象。搜索符号可能需要很长时间,   特别是当加载了很多名称空间时。

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