29
Scala Actors Scalable Multithreading on the JVM Philipp Haller Ph.D. candidate Programming Methods Lab EPFL, Lausanne, Switzerland

Scala Actors - LAMP | EPFL

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Scala Actors - LAMP | EPFL

Scala Actors

Scalable Multithreading on the JVM

Philipp Haller

Ph.D. candidateProgramming Methods LabEPFL, Lausanne, Switzerland

Page 2: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 2/23

The free lunch is over!

● Software is concurrent– Interactive applications– Web services– Distributed software

● Hardware is concurrent– Hyper­threading– Multi­cores, Many­cores– Grid computing

Page 3: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 3/23

Concurrency on the JVM

Threads and locks (synchronized):● Error­prone [Ousterhout96]

– races vs. deadlock, not composable

● Correct solutions often don't scale– memory consumption, lock contention

● Debugging and testing is hard– hard to reproduce executions (non­determinism)

Page 4: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 4/23

Outline

● Overview of Scala Actors● Example● Event­based Actors● The lift Web Framework● Performance● Conclusion

Page 5: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 5/23

Scala Actors

● Light­weight concurrent processes– Actor model (Erlang­style processes)– Asynchronous message passing– Expressive pattern matching

● Unify threads and events (efficient, scalable)● Automatically mapped to multiple JVM threads

– leverage multi­core processors

● No inversion of control

Page 6: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 6/23

What is an actor?

Page 7: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 7/23

Actors in a Nutshell

● Actors encapsulate state and behavior (like objects)

● Actors are logically active (unlike most objects)● Actors communicate through asynchronous 

message passing (non­blocking send, blocking receive)

Page 8: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 8/23

Exampleclass Ping(count: int, pong: Pong) extends Actor { def act() { }}

analogous to... extends Thread... def run() { ... }

Page 9: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 9/23

Message Send/Receiveclass Ping(count: int, pong: Pong) extends Actor { def act() {

pong ! 'Ping

receive { case 'Pong =>

}

}}

Page 10: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 10/23

The “Ping” Actorclass Ping(count: int, pong: Pong) extends Actor { def act() { var pingsLeft = count - 1 pong ! 'Ping while (true) { receive { case 'Pong => Console.println("Ping: 'Pong received") if (pingsLeft > 0) { Thread.sleep(500) pong ! 'Ping pingsLeft -= 1 } else { pong ! 'Stop exit() } } } }}

Page 11: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 11/23

Library Features

val pong = actor { while (true) { receive { case 'Ping => Console.println("Pong: 'Ping received") Thread.sleep(500) sender ! 'Pong case 'Stop => exit() } }}

“Inline” definition of actors:  actor {    ...  }

Implicit sender Ids: sender

Page 12: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 12/23

Futures

● Invoke asynchronous operation, returning a future (a place­holder for the reply) used to– wait for reply (blocking)– test whether reply available (non­blocking)

abstract class Future[T] extends Function0[T] { def isSet: boolean}

trait Function0[+R] extends AnyRef { def apply(): R}

Page 13: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 13/23

Futures: Examples

val ft = a !! Msg // send message, ft is a future...val res = ft() // await future ft

val ft1 = a !! Msgval ft2 = b !! Msgval ft3 = c !! Msg...val results = awaitAll(500, ft1, ft2, ft3)// returns a `List[Option[Any]]' holding the results

val res = awaitEither(ft1, ft2)

val ft = future { // define ad-hoc future ...}

Page 14: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 14/23

More Library Features

● receiveWithin(timeout)

● Channels (type­safe communication)● Java threads are Actors (automatically)● Linking Actors (monitoring)● Pluggable schedulers● Remote Actors

– over TCP, JXTA not yet released

Page 15: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 15/23

Event­based Actors

● Do not consume a thread● Very light­weight representation at run­time

– closure object (similar to a Runnable)

● Use react instead of receive● Restriction:

– call to react does not return– at the end: exit or call rest of computation– shortcuts for sequence and looping

Page 16: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 16/23

The “Ping” Actor ­ Event­basedclass Ping(count: int, pong: Pong) extends Actor { def act() { var pingsLeft = count - 1 pong ! 'Ping loop { react { case 'Pong => Console.println("Ping: 'Pong received") if (pingsLeft > 0) { Thread.sleep(500) pong ! 'Ping pingsLeft -= 1 } else { pong ! 'Stop exit() } } } }}

Page 17: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 17/23

The lift Web Framework

● 3rd party web framework● Compatible with any 2.4 servlet engine● Multi­threaded, scalable● Scala Actors used for critical parts

– Session management (Session Actors)– Dynamic content (Controller Actors)

● update asynchronously, send updates to Page Actors● Page Actor updates packaged as DOM­modifying 

JavaScript sent back to browser

Page 18: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 18/23

lift: Actor Example

class Clock extends ControllerActor { ActorPing.schedule(this, Tick, 10000L)

def render = bind("time" -> Text(timeNow.toString))

override def lowPriority: PartialFunction[Any, Unit] = { case Tick => reRender ActorPing.schedule(this, Tick, 10000L) }}

renders Controller and sends update to all Page Actors on which Controller exists

schedule a Tick message in 10 seconds

Page 19: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 19/23

Performance

Token passes per sec. in ring of processes● Java Threads: only up to 5000 threads, throughput 

breaks in● Scala Actors: constant throughput, up to 1.200.000 actors

Page 20: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 20/23

Scalability on Multi­Cores

● Micro­benchmarks run on 4­way dual­core Opteron machine (8 cores total)

● Compared to Doug Lea's FJTask framework for Java

Page 21: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 21/23

Performance

Page 22: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 22/23

Summary: Performance

● Millions of actors, constant throughput● Scalability on multi­cores without changes in 

program● Real­life experience with lift web framework1):

1) http://blog.lostlake.org/index.php?/archives/46­Some­more­Rails­to­lift­code­examples.html

Page 23: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 23/23

Scala Actors: Take Home

● Multi­threading on the JVM made easier and more scalable

● Used in real­world frameworks● Included in Scala standard library● Documentation/Tutorial at 

http://lamp.epfl.ch/~phaller/● Try it out: http://scala­lang.org● Send me mail: [email protected]

Page 24: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 24/23

Asynchronous Web Services

● Trend towards rich, responsive web applications– e.g. Gmail, Google calendar– technologies such as AJAX

● Responsiveness, performance, scalability● Asynchronicity is key

Problem: Asynchronicity is hard

Page 25: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 25/23

Asynchronicity is hard

def httpFetch(queryURL: String) = { val req = new XmlHttpRequest req.addOnReadyStateChangedListener(new PropertyChangeListener() { override def propertyChange(evt: PropertyChangeEvent) { if (evt.getNewValue() == ReadyState.LOADED) { val response = req.getResponseText() httpParseResponse(response) } } }) try { req.open(Method.GET, new URL(queryURL)) req.send() } catch { case e: Throwable => ... }} Typical asynchronous 

HTTP document fetch

Page 26: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 26/23

val res = evt...

Client Server

Page 27: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 27/23

Problems of Inversion of Control

● Hard to understand control­flow– reconstruct entire call­graph

● Manual stack management– handler code not defined where event is handled– local variables, parameters etc. not accessible

● Managing resources (files, sockets) becomes even harder– often long­lived, used in several event handlers– when is a missing close() a leak?

Page 28: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 28/23

val res = evt...

Client Server

Wrapper Actor

Message sends

Page 29: Scala Actors - LAMP | EPFL

May 2007 Scala Actors – Philipp Haller, EPFL 29/23

Avoiding Inversion of Control

val fetcher = actor { loop { react { case HttpFetch(url) => httpFetch(url) } }}

Wrapper:

fetcher ! HttpFetch("http://www.epfl.ch")// do some overlapping computationreact { // wait for response case Response(content) => // process response}

Client: