[SCALA] 스칼라의 게으른 발의 (숨겨진) 비용은 무엇입니까?
SCALA스칼라의 게으른 발의 (숨겨진) 비용은 무엇입니까?
스칼라의 한 편리한 기능은 필요의 때까지 발의 평가 (처음 액세스에서) 지연 게으른 발입니다.
물론, 게으른 발은 약간의 오버 헤드를 가지고 있어야합니다 - 어딘가 스칼라 값이 이미 평가되었으며, 여러 스레드가 동시에 처음으로 값을 액세스하려고 할 수 있기 때문에 평가가 동기화해야하는지 여부를 추적해야합니다.
정확하게 동기화하고 더 이상 비용이 있습니다 무엇, 그것은 평가되었는지의 경우 추적 할 게으른 발과 관련된 숨겨진 부울 플래그가있다 - 정확히 게으른 발의 비용은 무엇입니까?
또한, 나는 이렇게 생각 :
class Something {
lazy val (x, y) = { ... }
}
이 두 개의 별도의 게으른 놈들의 X를 가진 동일와 y가 아니면 쌍 (x, y)에 대한 한 번만 오버 헤드를받을 수 있나요?
해결법
-
==============================
1.이 스칼라 메일 링리스트에서 가져온 Java 코드 (오히려 바이트 이상)의 측면에서 게으른의 구현 세부 사항을 제공한다 :
이 스칼라 메일 링리스트에서 가져온 Java 코드 (오히려 바이트 이상)의 측면에서 게으른의 구현 세부 사항을 제공한다 :
class LazyTest { lazy val msg = "Lazy" }
다음 Java 코드에 해당 뭔가 컴파일 :
class LazyTest { public int bitmap$0; private String msg; public String msg() { if ((bitmap$0 & 1) == 0) { synchronized (this) { if ((bitmap$0 & 1) == 0) { synchronized (this) { msg = "Lazy"; } } bitmap$0 = bitmap$0 | 1; } } return msg; } }
-
==============================
2.컴파일러는 초기화 (여부)로서 플래그 여러 지연 필드 클래스 레벨 맵 INT 필드의 배열 및 비트 맵의 적절한 XOR이 필요하다고되어 있으면 동기 블록의 타겟 필드를 초기화 같습니다.
컴파일러는 초기화 (여부)로서 플래그 여러 지연 필드 클래스 레벨 맵 INT 필드의 배열 및 비트 맵의 적절한 XOR이 필요하다고되어 있으면 동기 블록의 타겟 필드를 초기화 같습니다.
사용 :
class Something { lazy val foo = getFoo def getFoo = "foo!" }
샘플 바이트 코드를 생성합니다 :
0 aload_0 [this] 1 getfield blevins.example.Something.bitmap$0 : int [15] 4 iconst_1 5 iand 6 iconst_0 7 if_icmpne 48 10 aload_0 [this] 11 dup 12 astore_1 13 monitorenter 14 aload_0 [this] 15 getfield blevins.example.Something.bitmap$0 : int [15] 18 iconst_1 19 iand 20 iconst_0 21 if_icmpne 42 24 aload_0 [this] 25 aload_0 [this] 26 invokevirtual blevins.example.Something.getFoo() : java.lang.String [18] 29 putfield blevins.example.Something.foo : java.lang.String [20] 32 aload_0 [this] 33 aload_0 [this] 34 getfield blevins.example.Something.bitmap$0 : int [15] 37 iconst_1 38 ior 39 putfield blevins.example.Something.bitmap$0 : int [15] 42 getstatic scala.runtime.BoxedUnit.UNIT : scala.runtime.BoxedUnit [26] 45 pop 46 aload_1 47 monitorexit 48 aload_0 [this] 49 getfield blevins.example.Something.foo : java.lang.String [20] 52 areturn 53 aload_1 54 monitorexit 55 athrow
지연 발 (X, Y) = {...}과 같은 튜플에 이니셜 값은 동일한 메커니즘을 통해 캐시를 중첩했다. 튜플 결과 느리게 평가 캐시이며, x 또는 y 중 하나의 액세스는 튜플 평가를 트리거한다. 튜플의 개별 값을 추출 독립적 느리게 (캐시 된) 수행된다. 따라서 상기 이중 인스턴스화 코드는 x, y 및 Tuple2 유형의 필드 1 $ X를 생성한다.
-
==============================
3.스칼라 2.10, 게으른 값과 같은 :
스칼라 2.10, 게으른 값과 같은 :
class Example { lazy val x = "Value"; }
다음과 같은 자바 코드를 유사한 바이트 코드로 컴파일한다 :
public class Example { private String x; private volatile boolean bitmap$0; public String x() { if(this.bitmap$0 == true) { return this.x; } else { return x$lzycompute(); } } private String x$lzycompute() { synchronized(this) { if(this.bitmap$0 != true) { this.x = "Value"; this.bitmap$0 = true; } return this.x; } } }
비트 맵 부울로 표시합니다. 다른 필드를 추가 할 경우, 컴파일러는 바이트로 즉, 2 개 이상의 값을 표시 할 수있는에 필드의 크기를 증가시킬 것이다. 이것은 단지 거대한 클래스에 간다.
이 작동하지만 왜 당신이 궁금 할 것이다? 비 휘발성 x 값 메모리에 플러시되도록 동기화 블록에 들어갈 때 스레드 로컬 캐시는 삭제되어야한다. 이 블로그 기사에 대한 설명을 제공합니다.
-
==============================
4.스칼라 SIP-20는 더 정확 게으른 발의 새로운 구현을 제안하지만 ~ "현재"버전보다 25 % 느리게.
스칼라 SIP-20는 더 정확 게으른 발의 새로운 구현을 제안하지만 ~ "현재"버전보다 25 % 느리게.
제안 된 구현은 아래와 같다 :
class LazyCellBase { // in a Java file - we need a public bitmap_0 public static AtomicIntegerFieldUpdater<LazyCellBase> arfu_0 = AtomicIntegerFieldUpdater.newUpdater(LazyCellBase.class, "bitmap_0"); public volatile int bitmap_0 = 0; } final class LazyCell extends LazyCellBase { import LazyCellBase._ var value_0: Int = _ @tailrec final def value(): Int = (arfu_0.get(this): @switch) match { case 0 => if (arfu_0.compareAndSet(this, 0, 1)) { val result = 0 value_0 = result @tailrec def complete(): Unit = (arfu_0.get(this): @switch) match { case 1 => if (!arfu_0.compareAndSet(this, 1, 3)) complete() case 2 => if (arfu_0.compareAndSet(this, 2, 3)) { synchronized { notifyAll() } } else complete() } complete() result } else value() case 1 => arfu_0.compareAndSet(this, 1, 2) synchronized { while (arfu_0.get(this) != 3) wait() } value_0 case 2 => synchronized { while (arfu_0.get(this) != 3) wait() } value_0 case 3 => value_0 } }
2013 년 6 월이 SIP는 승인되지 않았습니다. 나는 메일 링리스트의 논의를 기반으로 스칼라의 이후 버전에서는 승인을 포함 할 가능성이 있다고 예상한다. 따라서, 당신이 다니엘 스피 웍의 관찰에 유의하는 것이 현명 할 것 같습니다 :
-
==============================
5.나는이 문제에 관한 https://dzone.com/articles/cost-laziness으로 게시물을 작성했습니다
나는이 문제에 관한 https://dzone.com/articles/cost-laziness으로 게시물을 작성했습니다
간단히 말해서, 페널티은 실제로 당신이 그것을 무시할 수 있도록 작다.
-
==============================
6.http://www.javaworld.com/javaworld/jw-05-2001/jw-0525-double.html?page=1 이중 체크 잠금에서 언급 한 바와 같이 게으른 스칼라에 의해 생성 된 bycode을 감안할 때, 그것은 스레드 안전 문제를 겪을 수
http://www.javaworld.com/javaworld/jw-05-2001/jw-0525-double.html?page=1 이중 체크 잠금에서 언급 한 바와 같이 게으른 스칼라에 의해 생성 된 bycode을 감안할 때, 그것은 스레드 안전 문제를 겪을 수
from https://stackoverflow.com/questions/3041253/whats-the-hidden-cost-of-scalas-lazy-val by cc-by-sa and MIT license
'SCALA' 카테고리의 다른 글
[SCALA] 스칼라에서 ETA 확장은 무엇입니까? (0) | 2019.10.31 |
---|---|
[SCALA] csv 파일을 변환하는 방법에 지붕 EET을 (0) | 2019.10.31 |
[SCALA] 스칼라에서 전체 파일을 읽기? (0) | 2019.10.31 |
[SCALA] 스칼라에서 적용되는 기능은 무엇입니까? (0) | 2019.10.31 |
[SCALA] 스칼라의 상징적 사업자 모두가 무엇을 의미합니까? (0) | 2019.10.30 |