11

꽤 계산 집약적 인 프로그램에서 스칼라를 사용할 것을 고려하고 있습니다. 코드의 C++ 버전을 프로파일 링하면 Lazy 평가를 통해 상당한 이점을 얻을 수 있다는 것을 알 수 있습니다. 나는 Scala 2.9.1에서 그것을 시도해 보았고 실제로 그것을 좋아했다. 그러나 클래스를 디 컴파일러를 통해 실행할 때 구현이 올바르게 보이지 않았습니다. 나는 그것을 디 컴파일 할 때이것은 스칼라 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) 
    { 
    } 
} 

저에게있어, 반환 블록은 잘못된 위치에 있으며, 항상 잠금을 획득하게됩니다. 이것은 실제 코드가 수행 할 수는 없지만이를 확인할 수는 없습니다. 누구나 내가 가짜 역 컴파일을했다는 것을 확인하거나 부인할 수 있습니까? 그리고 게으른 구현은 다소 합리적입니다 (즉, 값을 계산할 때만 잠그고 후속 호출에 대해 잠금을 얻지 못합니다).

고마워요! http://java.decompiler.free.fr/?q=jdgui

+0

전산 집중적으로 자물쇠를하고 싶습니까? –

+0

아니요, 필요한 경우에만 계산할 항목이 많아서 계산 결과를 캐시에 저장하고 싶습니다. 구현에 따라 lazy는 내가 원하는 것을 정확하게 수행합니다. 잠금을 지정하지 않으면 더 좋을 것입니다.하지만이 질문의 핵심은 아닙니다. – fbl

+1

글쎄, 나는 계산 집약적 인 C/C++/Fortran 코드 (제약 시뮬레이션)에 대해 많은 조정을 해왔다. 내가 사용하는 방법은 [This is] (http://stackoverflow.com/questions/375913/what-can-i-use-to-profile-c-code-in-linux/378024#378024)입니다. (당신이 항상 명확하게 말하더라도, 프로파일 러를 항상 믿을 수는 없습니다.) –

답변

9

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 (1.5부터) 안전하고, 매우 빠르게 두 번 확인 잠금입니다.

자세한 내용 : 그들은 synchronized(this) { ... }에 의해 보호되므로

What's the (hidden) cost of Scala's lazy val?

, 당신은 클래스의 여러 게으른 발 구성원이있는 경우, 그 중 하나가 한 번에 초기화 될 수 있음을 유의하십시오.

+0

감사! 2 개의 응답을 'correct'로 표시 할 수 있다면 그렇게 할 수 있습니다. 나는 약간 더 읽기 쉽기 때문에 이것을 선택했다.) 나는 게으른 필드가 한 번에 하나씩 초기화 될 수 있다는 사실을 완전히 알고있다. 이는 우리가 솔루션을 설계하는 방법에 영향을 미치거나 영향을 미칠 수 있지만, 분명히 그 결정을 알려줍니다. – fbl

9

내가 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 
+0

감사합니다. 2 개의 응답을 'correct'로 표시 할 수 있다면 그렇게 할 수 있습니다. 이 답변과 축약 모두 Lazy의 진정한 본질을 드러내고 있습니다. – fbl

+0

문제는 없지만,이 Retronym의 대답도 선호합니다. 이보다 더 새로운 것은 아닙니다. -Xprint : jvm 옵션. javap은 여전히 ​​스칼라를 신뢰하지 않는다면 최종 판사가 될 수 있습니다. –