Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/16.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
Performance 这是Scala2.9.1延迟实现中的一个bug,还是反编译的产物_Performance_Scala_Synchronization_Lazy Evaluation_Decompiling - Fatal编程技术网

Performance 这是Scala2.9.1延迟实现中的一个bug,还是反编译的产物

Performance 这是Scala2.9.1延迟实现中的一个bug,还是反编译的产物,performance,scala,synchronization,lazy-evaluation,decompiling,Performance,Scala,Synchronization,Lazy Evaluation,Decompiling,我正在考虑在一个计算量很大的程序上使用Scala。剖析代码的C++版本表明,我们可以从懒惰的评估中获益匪浅。我已经在Scala 2.9.1中试用过,非常喜欢它。然而,当我通过反编译器运行该类时,实现看起来并不完全正确。我假设这是反编译器的产物,但我想得到一个更确切的答案 考虑以下简单的例子: class TrivialAngle(radians : Double) { lazy val sin = math.sin(radians) } 当我反编译它时,我得到以下结果: import

我正在考虑在一个计算量很大的程序上使用Scala。剖析代码的C++版本表明,我们可以从懒惰的评估中获益匪浅。我已经在Scala 2.9.1中试用过,非常喜欢它。然而,当我通过反编译器运行该类时,实现看起来并不完全正确。我假设这是反编译器的产物,但我想得到一个更确切的答案

考虑以下简单的例子:

class TrivialAngle(radians : Double) 
{
    lazy val sin = math.sin(radians)
}
当我反编译它时,我得到以下结果:

import scala.ScalaObject;
import scala.math.package.;
import scala.reflect.ScalaSignature;

@ScalaSignature(bytes="omitted")
public class TrivialAngle
  implements ScalaObject
{
  private final double radians;
  private double sin;
  public volatile int bitmap$0;

  public double sin()
  {
    if ((this.bitmap$0 & 0x1) == 0);
    synchronized (this)
    {
      if (
        (this.bitmap$0 & 0x1) == 0)
      {
        this.sin = package..MODULE$.sin(this.radians);
        this.bitmap$0 |= 1; 
      } 
      return this.sin;
    }
  }

  public TrivialAngle(double radians)
  {
  }
}
对我来说,返回块位于错误的位置,您将始终获得锁。这不可能是真正的代码在做什么,但我无法确认这一点。有人能确认或否认我有一个虚假的反编译,并且延迟实现在某种程度上是合理的(即,只在计算值时锁定,而不为后续调用获取锁定?)

谢谢

作为参考,这是我使用的反编译器:

我用
javap-c
得到的结果与您的反编译不一致。特别是,当发现字段被初始化时,没有监视器输入。版本也是2.9.1。当然,仍然存在易失性访问所隐含的内存障碍,因此它并不是完全免费的。以
/
开头的评论是我的

public double sin();
  Code:
   0:   aload_0
   1:   getfield        #14; //Field bitmap$0:I
   4:   iconst_1
   5:   iand
   6:   iconst_0
   7:   if_icmpne       54 /// if getField & 1 == O goto 54, skip lock
   10:  aload_0
   11:  dup
   12:  astore_1
   13:  monitorenter
            /// 14 to 52 reasonably equivalent to synchronized block 
            /// in your decompiled code, without the return
   53:  monitorexit
   54:  aload_0
   55:  getfield        #27; //Field sin:D
   58:  dreturn        /// return outside lock
   59:  aload_1        /// (this would be the finally implied by the lock)
   60:  monitorexit
   61:  athrow
  Exception table:
   from   to  target type
    14    54    59   any

scala-Xprint:jvm
揭示了真实的故事:

[[syntax trees at end of jvm]]// Scala source: lazy.scala
package <empty> {
  class TrivialAngle extends java.lang.Object with ScalaObject {
    @volatile protected var bitmap$0: Int = 0;
    <paramaccessor> private[this] val radians: Double = _;
    lazy private[this] var sin: Double = _;
    <stable> <accessor> lazy def sin(): Double = {
      if (TrivialAngle.this.bitmap$0.&(1).==(0))
        {
          TrivialAngle.this.synchronized({
            if (TrivialAngle.this.bitmap$0.&(1).==(0))
              {
                TrivialAngle.this.sin = scala.math.`package`.sin(TrivialAngle.this.radians);
                TrivialAngle.this.bitmap$0 = TrivialAngle.this.bitmap$0.|(1);
                ()
              };
            scala.runtime.BoxedUnit.UNIT
          });
          ()
        };
      TrivialAngle.this.sin
    };
    def this(radians: Double): TrivialAngle = {
      TrivialAngle.this.radians = radians;
      TrivialAngle.super.this();
      ()
    }
  }
}
[[jvm末尾的语法树]]//Scala源代码:lazy.Scala
包装{
类使用ScalaObject扩展java.lang.Object{
@易失性保护变量位图$0:Int=0;
private[this]val弧度:Double=\uux;
lazy-private[this]变量sin:Double=\u0;


请注意,如果一个类中有多个惰性val成员,那么一次只能初始化其中一个,因为它们由
synchronized(this){…}保护

计算密集型,您想进行锁定吗?不,我有很多项,我只想在需要时进行计算,并且我希望在计算后缓存这些结果。根据实现情况,lazy会完全满足我的要求。如果我可以指定不锁定,那会更好,但这不是问题所在问题的关键。我已经对计算密集型C/C++/Fortran代码(制药模拟)做了大量调整。我使用的方法。(你不能总是相信分析器,即使它们说得很清楚。)Scala代码无法反编译为Java。它使用了有效字节码的功能,但没有Java等价物。我不是说这里发生的事情就是这样(尽管可能是这样)但是,如果你必须读字节码,java java C++分析器在“采样”模式中使用的非常有效。你知道一个好的分析器,它可以为Java堆栈采样吗?我过去使用的技术相当成功,但是我更喜欢配置文件。感谢!如果我能将2个响应标记为“正确”,我会的。这个答案和retronym的答案都揭示了懒惰的真正本质。没问题,我也更喜欢retronym的答案,更何况我对-Xprint:jvm选项并不陌生。如果你真的不信任scala,javap可能仍然是最终的判断,但如果它不信任,那就更好了说到这里。谢谢!如果我能将2个响应标记为“正确”,我会的。我选择这一个是因为它更可读;)我完全知道一个事实,即惰性字段一次只能初始化一个。这可能会,也可能不会影响我们构建解决方案的方式,但它肯定会通知决策。