2017-05-31 3 views
0

私は、システム内のイベントとイベントと最後に計算された値に応じて値を計算する関数を持っている:私は、この関数を呼び出すと複数の代わりに単一の同期ブロックを使用するようにこの実装を変更するにはどうすればよいですか?

私はこの振る舞いをしたい:

  • 新しいイベントがある場合は、それが必要新しいイベントが存在しない場合の結果をイベントと最後のメモ化値を使用して新しい値を計算し、memoize
  • 、それは私がCAの実装をここで

をメモ化最後の値をされて返す必要があります私と一緒に:

<!-- language: lang-scala --> 
class EventBasedMemo[Value, Event](initialValue: => Value, 
            buildValue: (Value, Event) => Value, 
            nextEvent: Option[Event] = None) { 

    lazy val memoValue: Value = 
    nextEvent.fold(initialValue)(event => buildValue(initialValue, event)) 

    def update(event: Event): EventBasedMemo[Value, Event] = 
    new EventBasedMemo(memoValue, buildValue, Option(event)) 

} 

type Value = Int 
type Event = String 
var callsCount = 0 

var memo = new EventBasedMemo[Value, Event](0, (value, event) => { 
    callsCount += 1 
    println(s"$callsCount $event") 
    value + 1 
}) 

memo = memo.update("A") 
memo = memo.update("B") 
memo = memo.update("C") 

memo.memoValue // 1 A 2 B 3 C 
memo.memoValue 

memo = memo.update("D") 

memo.memoValue // 4 D 

これはうまくいきます。しかし、問題はlazy valがフードの下で同期を使用しているため、計算に複数のネストされた同期が行われていることです。

同期を1つだけ使用するように変更するにはどうすればよいですか。

解決策を不変にしたい。

答えて

0

手動でメモを使用すると、同期ブロックを回避できます。しかし、マルチスレッドのシナリオでは、キャッシュを数回再計算することができます。計算に副作用がない場合(例のような印刷ステートメントはありません)にのみ、再計算することは安全です。

class EventBasedMemo[Value, Event](initialValue: => Value, 
            buildValue: (Value, Event) => Value, 
            nextEvent: Option[Event] = None) { 

    var cache: Option[Value] = None 

    def memoValue(): Value = { 
    cache match { 
     case None => 
     cache = Some(nextEvent.fold(initialValue)(event => buildValue(initialValue, event))) 
     cache.get 
     case Some(value) => value 
    } 
    } 

    def update(event: Event): EventBasedMemo[Value, Event] = 
    new EventBasedMemo(memoValue, buildValue, Option(event)) 

} 

あなたは本当に速い同期で怠惰な価値を持つようにしたい場合は、ReentrantReadWriteLockなどの読み取り/書き込みロックを見てみましょう。次のコードはデモだけであり、マルチスレッド環境で正しく動作するかどうかは不明です。

import java.util.concurrent.locks.ReentrantReadWriteLock 

class EventBasedMemo[Value, Event](initialValue: => Value, 
            buildValue: (Value, Event) => Value, 
            nextEvent: Option[Event] = None, 
            lock:ReentrantReadWriteLock = new ReentrantReadWriteLock()) { 

    var cache: Option[Value] = None 

    def memoValue(): Value = { 
    lock.readLock().lock() 
    val result = cache match { 
     case None => 
     lock.readLock().unlock() 
     lock.writeLock().lock() 
     cache = Some(nextEvent.fold(initialValue)(event => buildValue(initialValue, event))) 
     lock.writeLock().unlock() 
     lock.readLock().lock() 
     cache.get 
     case Some(value) => value 
    } 
    lock.readLock().unlock() 
    result 
    } 

    def update(event: Event): EventBasedMemo[Value, Event] = 
    new EventBasedMemo(memoValue, buildValue, Option(event), lock) 

} 
関連する問題