Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Scala'是否合理;s比较性能基准的回复?_Scala_Performance Testing_Read Eval Print Loop - Fatal编程技术网

使用Scala'是否合理;s比较性能基准的回复?

使用Scala'是否合理;s比较性能基准的回复?,scala,performance-testing,read-eval-print-loop,Scala,Performance Testing,Read Eval Print Loop,Scala的REPL是交互式测试某些代码片段的绝佳平台。最近,我一直在使用REPL进行一些性能比较,以重复执行一个操作,并比较测量挂钟时间 下面是我最近创建的一个示例,用于帮助回答一个SO问题[1][2]: // Figure out the perfomance difference between direct method invocation and reflection-based method.invoke def invoke1[T,U](obj:Any, method:Meth

Scala的REPL是交互式测试某些代码片段的绝佳平台。最近,我一直在使用REPL进行一些性能比较,以重复执行一个操作,并比较测量挂钟时间

下面是我最近创建的一个示例,用于帮助回答一个SO问题[1][2]:

// Figure out the perfomance difference between direct method invocation and reflection-based method.invoke

def invoke1[T,U](obj:Any, method:Method)(param:T):U = method.invoke(obj,Seq(param.asInstanceOf[java.lang.Object]):_*) match { 
    case x: java.lang.Object if x==null => null.asInstanceOf[U]
    case x => x.asInstanceOf[U]
}

def time[T](b: => T):(T, Long) = {
    val t0 = System.nanoTime()
    val res = b
    val t = System.nanoTime() - t0
    (res,t )
}

class Test {
  def op(l:Long): Long = (2 until math.sqrt(l).toInt).filter(x=>l%x==0).sum
}

val t0 = new Test

val method = classOf[Test].getMethods.find(_.getName=="op").get

def timeDiff = {
  val (timeDirectCall,res) = time { (0 to 1000000).map(x=>t0.op(x)) }
  val (timeInvoke, res2) = time { (0 to 1000000).map(x=>{val res:Long=invoke1(t0,method)(x);res}) }
  (timeInvoke-timeDirectCall).toDouble/timeDirectCall.toDouble
}


//scala> timeDiff
//res60: Double = 2.1428745665357445
//scala> timeDiff
//res61: Double = 2.1604176409796683
在另一个例子中,我已经生成了MM个随机数据点来比较一个开源项目的并发模型。REPL非常适合在没有代码编译测试周期的情况下使用不同的配置

我知道常见的基准测试陷阱,比如JIT优化和热身的需要

我的问题是:

  • 在使用时是否需要考虑任何REPL特定的元素 是否需要执行宏观基准的微观比较

  • 相对使用时,这些测量值可靠吗?i、 e.他们能回答以下问题吗:
    A
    B
    快吗

  • 相同代码的预删除执行是否是jit的良好预热 编译程序

  • 还有其他需要注意的问题吗

[1]


[2] 这是一个很好的问题。我无法想象为什么会有人否决它

其中一条评论完全错误的事实表明,REPL需要在scala-lang.org的faq或教程中占有一席之地。快速搜索后,我找不到这篇描述性文章

答案是肯定的,REPL做了你期望的事情

关于为什么这个问题很有趣:REPL感觉是动态的,但实际上是静态编译的。正如链接页面上的即兴评论所说,它“跨越两个世界”

REPL将每一行编译成它自己的包装对象。每个这样的对象都从交互会话的历史记录中导入符号,这就是代码神奇地引用前几行的方式。一切都是编译的,所以当它运行时,可以说它是在JVM上本机运行的;没有额外的一层解释器。这就是REPL的杀手级设计特性

这就是为什么您的问题的答案是肯定的,您的代码以编译代码的速度运行。调用方法不需要重新编译所有历史

表明其他人对时间和微基准有同样的疑问

目前,有一种方法可以自定义REPL包装代码行的方式。微基准标记是一个有趣的用例,其中代码可以包装在任意框架中进行基准测试。这很快就会到来

基准框架应注意预热。由于提交给REPL的每个表达式都是单独编译的(尽管是由同一个编译器编译的),因此您会注意到,第一次可以冷调用方法,第二次可以暖调用方法(scalac的模内联)

警告:

使用基于
-Yrepl类的
或小心不要将计算放在包装对象的静态初始值设定项中


而且,不那么隐蔽。

REPL将代码包装到它自己的内部环中(这样你就可以重新定义VAL/VAR/functions/classes/objects并做其他讨厌的事情),所以基本上你要衡量的是编译代码的时间,包装代码的时间,以及最终的实际执行时间,因为(但您说您知道最后一个组件不可靠)。显然,这样的测量是不可靠的。@om nom nom wrap&COMPLE基本上是一次性的,这将导致一些开销,但对于任何正在测试的选项来说,这将是相同的开销,所以相对分数应该仍然具有代表性,或者不具有代表性?例如,在上面的示例中,它显示了大约2倍的速度,这是足够好的信息。感谢r这是一个很好的答案和指针。据你所知,代码
:粘贴
'd和逐行输入之间有什么区别吗?我应该选择一种方法而不是另一种方法吗?@maasg粘贴的代码被包装在单个对象和编译单元中(这就是为什么必须粘贴伴随对象的原因).在2.11中:加载文件是逐行的,但:粘贴文件是tout court。我刚刚将我的-I init.script更改为:load imports.script,这比编译每一行都快得多。引用对象需要通常的$MODULE deref,但几乎没有性能损失。因此有一些编译时边缘情况,但在该级别的运行时没有开销.typo:s/:load imports.script/:paste imports.script,显然。加快repl启动的一种方法是将init的运行次数减少到一次。