【问题标题】:does white space slow down processing空白是否会减慢处理速度
【发布时间】:2013-03-12 17:35:15
【问题描述】:

我有大量数据要分析,我在编写代码时倾向于在单词或变量名之间留出空格,所以问题是,如果效率是第一要务,空格是否有成本?

c

【问题讨论】:

  • 空白的数量不应与数据量相关

标签: r


【解决方案1】:

对于第一、第二、第三,...,近似值,不,它根本不会花费你任何时间。

您花在按空格键上的额外时间比运行时的成本高出几个数量级(根本不重要)。

更大的成本将来自任何因遗漏空格而导致的可读性下降,这会使代码(对于人类)更难解析。

【讨论】:

    【解决方案2】:

    一句话,不!

    library(microbenchmark)
    
    f1 <- function(x){
        j   <- rnorm( x , mean = 0 , sd = 1 )         ;
        k   <-      j    *      2         ;
        return(    k     )
    }
    
    f2 <- function(x){j<-rnorm(x,mean=0,sd=1);k<-j*2;return(k)}
    
    
    microbenchmark( f1(1e3) , f2(1e3) , times= 1e3 )
        Unit: microseconds
         expr     min       lq  median      uq      max neval
     f1(1000) 110.763 112.8430 113.554 114.319  677.996  1000
     f2(1000) 110.386 112.6755 113.416 114.151 5717.811  1000
    
    #Even more runs and longer sampling
    microbenchmark( f1(1e4) , f2(1e4) , times= 1e4 )
      Unit: milliseconds
          expr      min       lq   median       uq       max neval
     f1(10000) 1.060010 1.074880 1.079174 1.083414 66.791782 10000
     f2(10000) 1.058773 1.074186 1.078485 1.082866  7.491616 10000
    

    编辑

    似乎使用微基准测试是不公平的,因为表达式在循环中运行之前就已被解析。但是使用source 应该意味着每次迭代都必须解析源代码并删除空格。所以我将函数保存到两个单独的文件中,文件的最后一行是函数的调用,例如,我的文件 f2.R 看起来像这样:

    f2 <- function(x){j<-rnorm(x,mean=0,sd=1);k<-j*2;return(k)};f2(1e3)
    

    我像这样测试它们:

    microbenchmark( eval(source("~/Desktop/f2.R")) ,  eval(source("~/Desktop/f1.R")) , times = 1e3)
      Unit: microseconds
                               expr     min       lq   median      uq       max neval
     eval(source("~/Desktop/f2.R")) 649.786 658.6225 663.6485 671.772  7025.662  1000
     eval(source("~/Desktop/f1.R")) 687.023 697.2890 702.2315 710.111 19014.116  1000
    

    以及 1e4 复制的差异的直观表示....

    也许它在函数被重复解析的情况下确实产生了微小的差异,但在正常用例中不会发生这种情况。

    【讨论】:

    • 大声笑,我开始用更简单的函数 (1+2) 做同样的事情,但我使用了 10000000 次复制,所以你得到的结果更快。 :) (有点令人惊讶的是,rbenchmark 给出了 53s 和 44s 的结果 .. 有利于空格)
    • 你确定这是一个公平的测试吗?我强烈的猜测是函数体只被解析一次,最初,完全在微基准循环之外!
    • 是的,这是修辞,虽然我对答案有强烈的怀疑。如果identical(body(f1), body(f2))(或我尝试过的许多变体之一)是TRUE,我会完全有信心,但事实并非如此,我不知道为什么。很高兴了解更多信息。
    • 看起来它们相同的(直到附加到已解析函数体的各种srcref 属性)。必须有一种更优雅的方法来检查这一点,但至少以下方法有效:a &lt;- body(f1); b &lt;- body(f2); attributes(a) &lt;- attributes(b) &lt;- NULL; identical(a,b)
    • 我也是。在调用函数之前进行解析的一个提示是尝试这样的事情:j &lt;- function (x) a &lt;- b c &lt;- d。您收到的错误消息来自解析器,它告诉您这不是一个语法有效的表达式。
    【解决方案3】:

    但是,不,不是:

    TL;DR 运行脚本来删除空格可能比通过删除空格节省的时间要长。

    @Josh O'Brien 真的一针见血。但我无法抗拒基准测试

    如您所见,如果您正在处理数量级为 1 亿条的行,那么您将看到一个微不足道的阻碍。 但是 有这么多行,它们很有可能成为至少一个(如果不是数百个)热点, 与grep消除所有空白相比,简单地改进其中之一中的代码会给您带来更快的速度。

      library(microbenchmark)
    
      microbenchmark(LottaSpace = eval(LottaSpace), NoSpace = eval(NoSpace), NormalSpace = eval(NormalSpace), times=10e7)
    
      @ 100 times;  Unit: microseconds
               expr   min     lq median     uq    max
      1  LottaSpace 7.526 7.9185 8.1065 8.4655 54.850
      2 NormalSpace 7.504 7.9115 8.1465 8.5540 28.409
      3     NoSpace 7.544 7.8645 8.0565 8.3270 12.241
    
      @ 10,000 times;  Unit: microseconds    
               expr   min    lq median    uq      max
      1  LottaSpace 7.284 7.943  8.094 8.294 47888.24
      2 NormalSpace 7.182 7.925  8.078 8.276 46318.20
      3     NoSpace 7.246 7.921  8.073 8.271 48687.72
    

    地点:

      LottaSpace <- quote({
            a            <-            3
            b                  <-                  4   
            c         <-      5
            for   (i            in      1:7)
                  i         +            i
      })
    
    
      NoSpace <- quote({
      a<-3
      b<-4
      c<-5
      for(i in 1:7)
      i+i
      })
    
      NormalSpace <- quote({
       a <- 3
       b <- 4 
       c <- 5
       for (i in 1:7)
       i + i
      })
    

    【讨论】:

      【解决方案4】:

      这可能影响的唯一部分是将源代码解析为令牌。我无法想象解析时间的差异会很大。但是,您可以通过使用 compiler 包的 compilecmpfun 函数编译函数来消除此方面。然后解析只进行一次,任何空格差异都不会影响执行时间。

      【讨论】:

      • 我很确定一个函数定义只解析一次,不管你是否compile代码。 compiler 包通过避免重复编译函数来加速代码,对吧?
      • @JoshO'Brien 这可能是对的。我不确定。如果编译了就不会再解析了,但是如果不编译就不确定会不会再解析了。
      【解决方案5】:

      在性能上应该没有差异,尽管:

      fn1<-function(a,b) c<-a+b
      fn2<-function(a,b) c <- a + b
      
      library(rbenchmark)
      
      > benchmark(fn1(1,2),fn2(1,2),replications=10000000)
             test replications elapsed relative user.self sys.self user.child
      1 fn1(1, 2)     10000000   53.87    1.212      53.4     0.37         NA
      2 fn2(1, 2)     10000000   44.46    1.000      44.3     0.14         NA
      

      microbenchmark相同:

      Unit: nanoseconds
            expr min  lq median  uq      max neval
       fn1(1, 2)   0 467    467 468 90397803 1e+07
       fn2(1, 2)   0 467    467 468 85995868 1e+07
      

      所以第一个结果是假的..

      【讨论】:

        猜你喜欢
        • 2011-04-12
        • 1970-01-01
        • 1970-01-01
        • 2019-04-04
        • 1970-01-01
        • 2013-06-18
        • 2022-06-10
        • 2014-09-20
        • 1970-01-01
        相关资源
        最近更新 更多