Pellucid stm

Post on 18-May-2015

1.168 views 1 download

Tags:

description

Lightning Talk on Software Transactional Memory in Scala. The Actors Pattern has gotten a lot of attention in the Scala ecosphere, but STM of often a good first solution for solving concurrency problems. It's odd that it hasn't had as much attention in the Scala world, so this talk aims to show how easy it is to use, and compare it to typical lock-based synchronization by showing how easy it is to make errors with lock-based synchronization

Transcript of Pellucid stm

SOFTWARE TRANSACTIONAL MEMORY@DUSTINWHITNEY

Alternative to lock-based synchronization

Analogous to database transactions

ACI (ACID with out the ‘D’)

Simple! (well… simplier)

WHAT IS STM?

libraryDependencies += ("org.scala-stm" %% "scala-stm" %

"0.7")

import scala.concurrent.stm._

val protectedInt = Ref(0)

atomic{ implicit transaction=> val currentValue = protectedInt.get protectedInt.set(currentValue + 1)}

WHAT DOES IT LOOK LIKE?

ATOMIC

val protectedInt = Ref(0)val anotherProtectedInt = Ref(0)

atomic{ implicit transaction => val currentValue = protectedInt.get protectedInt.set(currentValue + 1) val anotherCurrentValue = anotherProtectedInt.get anotherProtectedInt.set(anotherCurrentValue + 1)}

CONSISTENT

val protectedInt = Ref(0)

atomic{ transaction => val currentValue = protectedInt.get(transaction) protectedInt.set(currentValue + 1)(transaction)}

val protectedInt = Ref(0)

atomic{ implicit transaction => val currentValue = protectedInt.get protectedInt.set(currentValue + 1)}

ISOLATED

STM is not Durable

DURABLE

ADVANTAGES: DEADLOCK / LIVELOCK

val protectedInt = Ref(0)

atomic{ implicit transaction => val currentValue = protectedInt.get protectedInt.set(currentValue + 1)}

ADVANTAGES: PRIORITY INVERSION

val protectedInt = Ref(0)

atomic{ implicit transaction => val currentValue = protectedInt.get protectedInt.set(currentValue + 1)}

ADVANTAGES: COMPOSABILITY

val protectedInt = Ref(0)val anotherProtedtedInt = Ref(0)

atomic{ implicit transaction => val currentValue = protectedInt.get protectedInt.set(currentValue + 1) atomic{ implicit transaction => val anotherCurrentValue = anotherProtectedInt.get val anotherProctedInt.set(anotherCurrentValue + 1) }

}

GOTCHAS: IMMUTABILITY!

// bad!val badMap= Ref(new java.util.HashMap[String, Int]())val mutableMap = atomic{ implicit transaction => badMap.get }mutableMap.put(“Wrong!”, 666)

// goodval goodMap = Ref(Map(“Good” -> 7))atomic{ implicit transaction => val tempMap = goodMap.get goodMap.set(tempMap + (“Good” -> 777))}

GOTCHAS: REFERENTIAL TRANSPARENCY

//badval protectedString = Ref("This is a string")val time = System.currentTimeMillisatomic{ implicit transaction => if(time % 2 == 0) protectedString.set("Time was even") else protectedString.set("Time was odd")}

//goodatomic{ implicit transaction => val time = System.currentTimeMillis if(time % 2 == 0) protectedString.set("Time was even") else protectedString.set("Time was odd")}

EXTENDED EXAMPLE: STM

case class Account(number: Int, balance: Int)

val accounts = Ref(Map( 1 -> Account(1, 100), 2 -> Account(2, 100) ))

def transfer(to: Int, from: Int, amount: Int){ atomic{ implicit transaction => val map = accounts.get val toAccount = map(to) val fromAccount = map(from) accounts.set( map + (to -> (toAccount.copy(balance = toAccount.balance + amount))) + (from -> (fromAccount.copy(balance = fromAccount.balance - amount))) ) } }

EXTENDED EXAMPLE: SYNCHRONIZED

import java.util._private val accounts = new HashMap[Int, Account]()accounts.put(1, Account(1, 100))accounts.put(2, Account(2, 100))

def transfer(to: Int, from: Int, amount: Int){ accounts.synchronized{ val toAccount = accounts.get(to) val fromAccount = accounts.get(from) accounts.put(to, (toAccount.copy(balance = toAccount.balance + amount))) accounts.put(from, (fromAccount.copy(balance = fromAccount.balance - amount))) }}

EXTENDED EXAMPLE: SYNCHRONIZED2

import java.util.concurrent._private val accounts = ConcurrentHashMap[Int, Account]()accounts.put(1, Account(1, 100))accounts.put(2, Account(2, 100))

def transfer(to: Int, from: Int, amount: Int){ val toAccount = accounts.get(to) val fromAccount = accounts.get(from) toAccount.synchronized{ fromAccount.synchronized{ accounts.put(to, (toAccount.copy(balance = toAccount.balance + amount))) accounts.put(from, (fromAccount.copy(balance = fromAccount.balance - amount))) } }}

EXTENDED EXAMPLE: SYNCHRONIZED3

import java.util.concurrent._private val accounts = ConcurrentHashMap[Int, Account]()accounts.put(1, Account(1, 100))accounts.put(2, Account(2, 100))

def transfer(to: Int, from: Int, amount: Int){ val toAccount = accounts.get(to) val fromAccount = accounts.get(from) val (firstLock, secondLock) = if(to > from) (toAccount, fromAccount) else (fromAccount, toAccount) firstLock.synchronized{ secondLock.synchronized{ accounts.put(to, (toAccount.copy(balance = toAccount.balance + amount))) accounts.put(from, (fromAccount.copy(balance = fromAccount.balance - amount))) } }}

Questions?