55
Scalable Applications with Scala Nimrod Argov Tikal Knowledge

Scalable Applications with Scala

Embed Size (px)

Citation preview

Page 1: Scalable Applications with Scala

Scalable Applications

with Scala

Nimrod Argov

Tikal Knowledge

Page 2: Scalable Applications with Scala

What is a Scalable

Application?

Page 3: Scalable Applications with Scala

What is a Scalable

Application?

Scalability is the ability of a system,

network, or process to handle a growing

amount of work in a capable manner or its

ability to be enlarged to accommodate that

growth.

-- wikipedia.org

Page 4: Scalable Applications with Scala

What is a Scalable

Application?

Administrative - More

People using the

system, or more

programmers writing it

Page 5: Scalable Applications with Scala

What is a Scalable

Application?

Functional - Adding new

functionality with minimal

effort

Page 6: Scalable Applications with Scala

What is a Scalable

Application?

Geographical - Maintaining

performance, usefulness or

usability regardless of locale

specific user concentration

Page 7: Scalable Applications with Scala

What is a Scalable

Application?

Load - The ability of a

system to expand and

contract to accommodate

heavier or lighter loads

Page 8: Scalable Applications with Scala

Concurrency /

Parallelism

Optimizing CPU Usage Efficiency

Page 9: Scalable Applications with Scala

Scala

Scala brings together the Functional and Object

Oriented worlds, where until now both sides

considered the other to be totally wrong, or the

work of the devil.

-- Martin Oderski

Page 10: Scalable Applications with Scala

Fun!

Page 11: Scalable Applications with Scala

Java

java.util.concurrent

Locking

Mutable Shared State

Page 12: Scalable Applications with Scala

Java

When is it enough?

Page 13: Scalable Applications with Scala

Java

When is it enough?

Too Little - Race Conditions

Too Much - Loss of Parallelism / Deadlocks

Page 14: Scalable Applications with Scala

Immutability

Concurrency requires Immutability

Classes should be immutable unless there's a very good reason to

make them mutable....If a class cannot be made immutable, limit

its mutability as much as possible.

-- Effective

Java (Joshua Bloch)

Page 15: Scalable Applications with Scala

Immutability

//java

public final class Student

private final int id;

private final String name;

public Student(int id, String name){

this.id = id;

this.name = name;

}

.. getters…

}

Page 16: Scalable Applications with Scala

Immutability

//java

public final class Student

private final int id;

private final String name;

public Student(int id, String name){

this.id = id;

this.name = name;

}

.. getters…

}

Page 17: Scalable Applications with Scala

Immutability

//java

List<Student> students = new ArrayList<Student>();

List<Student> immutableStudents = Collections.unmodifiableList(students);

List<Students> ohBother = new CopyOnWriteArrayList<Student>();

Page 18: Scalable Applications with Scala

Immutability

//java

List<Student> students = new ArrayList<Student>();

List<Student> immutableStudents = Collections.unmodifiableList(students);

students.add(new Student(15, “Harry Potter”));

immutableStudents now shows a different list!

Page 19: Scalable Applications with Scala

Scala Collections

● Mutable/Immutable variants

● Immutable variant is imported by default

● Operations are Fast

● Cost of object creation is highly exaggerated by

programmers

Page 20: Scalable Applications with Scala

Scala Collections

● Set

● Map

● List

● Stream

● Vector

● Stack

● Queue

● Tree

Page 21: Scalable Applications with Scala

Scala Collections

Many Operations:

● ++ (add all)

● collect

● combinations

● contains

● count

● diff

● endsWith

● filter

● find

● flatMap

● flatten

● forEach

● intersect

● lift

● min

● max

● mkString

● partition

● permutations

● reduce

● reverse

Page 22: Scalable Applications with Scala

Scala Parallel

Collections

Motivation

“The hope was, and still is, that implicit parallelism behind

a collections abstraction will bring reliable parallel

execution one step closer to the workflow of mainstream

developers.”

--Scala Documentation

Page 23: Scalable Applications with Scala

Scala Parallel

Collections

Example: Calculate function over list of numbers

Page 24: Scalable Applications with Scala

Scala Parallel

Collections

Example: Calculate function over list of numbers

Java:

// Somehow cut the list to N parts

Page 25: Scalable Applications with Scala

Scala Parallel

Collections

Example: Calculate function over list of numbers

Java:

// Somehow cut the list to N parts

// Create ForkJoinTask (or Just a Runnable if pre JDK 6)

Page 26: Scalable Applications with Scala

Scala Parallel

Collections

Example: Calculate function over list of numbers

Java:

// Somehow cut the list to N parts

// Create ForkJoinTask (or Just a Runnable if pre JDK 6)

// Use ForkJoinPool to run the tasks

// Wait for all to finish (join)

Page 27: Scalable Applications with Scala

Scala Parallel

Collectionspublic class Operation extends RecursiveAction{

private List<Integer> numbers;

private List<Integer> results;

private int start, end;

public Operation(List<Integer> nums){

numbers = nums;

start = 0;

end = numbers.size();

}

protected void doComputation(){

for(int i = start; i < end; i++)

results.set(i, calculate(number));

}

}

Page 28: Scalable Applications with Scala

Scala Parallel

Collectionspublic class Operation extends RecursiveAction{

protected static int threshold = 1000;

...

public Operation(List<Integer> nums){ … }

protected void doComputation(){ … }

protected void compute(){

if (numbers.length < threshold)

doComputation();

else

invokeAll(new SumOperation(numbers, 0,

numbers.size() / 2),

new SumOperation(numbers, numbers.size() /

2, numbers.size());

}

}

Page 29: Scalable Applications with Scala

Scala Parallel

Collections

val myParallelList = someList.par

myParallelList map calculate(_)

Page 30: Scalable Applications with Scala

Scala Parallel

Collections

val myParallelList = someList.par

myParallelList map calculate(_)

5 8 12 7 13 86 14 2 37 23 67 41 1 77 24 95

Page 31: Scalable Applications with Scala

Scala Parallel

Collections

val myParallelList = someList.par

myParallelList map calculate(_)

5 8 12 7 13 86 14 2 37 23 67 41 1 77 24 95

5 8 12 7 13 86 14 2 37 23 67 41 1 77 24 95

Page 32: Scalable Applications with Scala

Scala Parallel

Collections

val myParallelList = someList.par

myParallelList map calculate(_)

5 8 12 7 13 86 14 2 37 23 67 41 1 77 24 95

5 8 12 7 13 86 14 2 37 23 67 41 1 77 24 95

11 22 66 11 55 22 66 55 99 33 88 88 55 22 77 11

Page 33: Scalable Applications with Scala

Scala Parallel

Collections

val myParallelList = someList.par

myParallelList map calculate(_)

5 8 12 7 13 86 14 2 37 23 67 41 1 77 24 95

5 8 12 7 13 86 14 2 37 23 67 41 1 77 24 95

11 22 66 11 55 22 66 55 99 33 88 88 55 22 77 11

11 22 66 11 55 22 66 55 99 33 88 88 55 22 77 11

Page 34: Scalable Applications with Scala

Scala Parallel

Collections

• ParArray

• ParVector

• mutable.ParHashMap

• mutable.ParHashSet

• immutable.ParHashMap

• immutable.ParHashSet

• ParRange

• ParTrieMap

Page 35: Scalable Applications with Scala

Scala Parallel

Collections

Each collection defines:

● Splitter

● Combiner

Default # of threads: how many cores have you got?

Underlying implementation depends on configuration

Page 36: Scalable Applications with Scala

Scala Parallel

Collections

ForkJoinTaskSupport (JDK 1.6 or higher)

ThreadPoolTaskSupport

ExecutionContextTaskSupport

Page 37: Scalable Applications with Scala

Scala Parallel

Collections

<<< WARNING… WARNING… >>>

Side Effects or Non-Associative operations will create

non-deterministic results!

Page 38: Scalable Applications with Scala

Scala Parallel

Collections

var sum = 0;

List(1 to 10000).par.forEach(sum += _)

List(1 to 10000).par.reduce(_-_)

Page 39: Scalable Applications with Scala

Scala Futures

Futures provide a nice way to reason about performing

many operations in parallel, in an efficient and non-

blocking way.

-- Scala Documentation

Page 40: Scalable Applications with Scala

Scala Futures

Future Promise

Page 41: Scalable Applications with Scala

Scala Futures

val p = Promise[T]

val f: Future[T] = p.future

Page 42: Scalable Applications with Scala

Java Futures

val p = Promise[T]

val f: Future[T] = p.future

// Java-like variant:

doSomeWork()

f.get()

Page 43: Scalable Applications with Scala

Efficient?

Page 44: Scalable Applications with Scala

Efficient?

Also, Java Futures are NOT Composable

Page 45: Scalable Applications with Scala

What We Want

Page 46: Scalable Applications with Scala

Callbacks

Thread 1

val p = Promise[T]

val f: Future[T] = p.future

Thread 2

f onComplete {

case Success(calcResult) = println(calcResult)

case Failure(t) = println(“Error: “ + t.getMessage)

}

Page 47: Scalable Applications with Scala

Callbacks

Thread 1

val p = Promise[T]

val f: Future[T] = p.future

Thread 2

f onComplete{

case Success(calcResult) = println(calcResult)

case Failure(t) = println(“Error: “ + t.getMessage)

}

Page 48: Scalable Applications with Scala

Try

Try[T]

Success[T](value: T)

Failure[T](t: throwable)

Page 49: Scalable Applications with Scala

Try

Try[T]

Success[T](value: T)

Failure[T](t: throwable)

Not Asynchronous

Page 50: Scalable Applications with Scala

Try

val result: Try[int] = calcSomeValue

result match{

case Success(n) = println(“The result is “ + n)

case Failure(t) = println(“Error: “ + t.getMessage)

}

Page 51: Scalable Applications with Scala

Monadic Combinators

val result: Int = calcSomeValue getOrElse -1

calcSomeValue.map(doSomethingWithVal).recover

(handleException)

Page 52: Scalable Applications with Scala

val rateQuote = future {

service.getCurrentValue(USD)

}

val purchase = rateQuote map { quote =>

if (isProfitable(quote)) service.buy(amount, quote)

else throw new Exception("not profitable")

}

purchase onSuccess {

case _ => println("Purchased " + amount + " USD")

}

Future Composition

Page 53: Scalable Applications with Scala

val usdQuote = future { service.getCurrentValue(USD) }

val chfQuote = future { service.getCurrentValue(CHF) }

val purchase = for {

usd <- usdQuote

chf <- chfQuote

if isProfitable(usd, chf)

} yield service.buy(amount, chf)

purchase onSuccess {

case _ => println("Purchased " + amount + " CHF")

}

Future Composition

Page 54: Scalable Applications with Scala

def generate = future { (random, random) }

def calculate(x:(Double, Double)) = future{ pow(x._1, x._2) }

def filter(y:Any) = y.toString.contains("22222")

while (true) {

for {

i <- generate

j <- calculate(i)

if filter(j)

}

println(j)

}

Pipe Example

Page 55: Scalable Applications with Scala