actors that unify threads and events - epfllampphaller/doc/actorsunify.pdf · 06/07/07 philipp...

30
Actors that Unify Threads and Events Philipp Haller, EPFL joint work with Martin Odersky, EPFL

Upload: others

Post on 03-Aug-2020

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

Actors that UnifyThreads and Events

Philipp Haller, EPFL

joint work with Martin Odersky, EPFL

Page 2: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 2/23

Implementing Concurrent Processes

● Thread­based– Behavior = body of designated method– Execution state = thread stack

– Examples: Java threads, POSIX threads

● Event­based– Behavior = set of event handlers– Execution state = object shared by handlers

– Examples: Java Swing, TinyOS

1

2

Page 3: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 3/23

Threads[Ousterhout96]

● Support multiple hardware cores (Good)● Behavior = sequential program (Good)● Heavyweight (Bad)

– High memory consumption● Pre­allocated stacks

– Lock contention bottleneck

● Synchronization using locks error­prone, not composable (Bad)

Page 4: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 4/23

Events: Remedy?[vonBehren03]

● Lightweight (Good)– Multiple events interleaved on single thread– Low memory consumption

● Automatic synchronization (Good)● No hardware support (Bad)● Inversion of control (Bad)

– Behavior != sequential program

Page 5: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 5/23

Rest of this Talk

● Programming with Actors in Scala● Unifying Threads and Events

– Programming Model– Lightweight Execution Environment

● Composing Actors● Selective Communication● Experimental Results

Page 6: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 6/23

Actors

● Model of concurrent processes introduced by Hewitt and Agha

● Upon reception of a message, an actor may– send messages to other actors– create new actors– change its behavior/state

● Most popular implementation: Erlang● But: No widespread adoption in languages for 

standard VMs (e.g. JVM, CLR)

Page 7: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 7/23

Actors in Scala

● Two principle operations (adopted from Erlang)

● Send is asynchronous; messages are buffered in actor's mailbox

● receive waits for message that matches any of the patterns msgpat_i

actor ! message // message send

receive { // message receive case msgpat_1 => action_1 ... case msgpat_n => action_n}

Page 8: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 8/23

Example: Producers

● Producers act like iterators, generate values concurrently with consumer:

● Methods produceValues (abstract) and produce inherited from class Producer

class InOrder(n: IntTree) extends Producer[Int] { def produceValues = traverse(n) def traverse(n: IntTree) = if (n != null) { traverse(n.left) produce(n.elem) traverse(n.right) } }

Page 9: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 9/23

Implementing Producers

Producers are implemented in terms of two actors.

● The producer actor runs produceValues:

abstract class Producer[T] extends Iterator[T] { def produceValues: Unit def produce(x: T) { coordinator ! Some(x) } private val producer = actor { produceValues; coordinator ! None }}

1

Page 10: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 10/23

Implementing Producers (2)

● The coordinator actor synchronizes requests from clients and values from the producer

2

val coordinator = actor { while (true) { receive { case Next => receive { case x: Option[_] => client ! x } } }}

Page 11: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 11/23

Lightweight Execution Environment

Actors (many)

Worker threads (few)Task queue

Page 12: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 12/23

closure => T3

T3

Creating Actors

{ // body}

actor

T1

T2

Page 13: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 13/23

Thread Mode: receive

● Scan messages in mailbox● If no message matches any 

of the patterns, suspend worker thread

● Otherwise, process first matching message

...receive{ case Msg(x) => // handle msg}...

1

2

3

Actor remains active

Page 14: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 14/23

Event Mode: react

...react{ case Msg(x) => // handle msg}

● Register message handler● Become passive 

(temporarily)

1

2

Actor becomes inactive

Page 15: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 15/23

Suspend in Event Mode

...react{ case Msg(x) => // handle msg}

Task Ti: Worker thread:try { // execute Ti} catch { case _: SuspendActorExc => // do nothing}

def react(f: PartialFunction[Any, Unit]): Nothing = { mailbox.dequeueFirst(f.isDefinedAt) match { case None => continuation = f; suspended = true case Some(msg) => ... } throw new SuspendActorException}

Exception:● Unwinds stack of 

actor/worker thread● Finishes current task

1

2

Page 16: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 16/23

Ti+2

Resume in Event Mode

{ case Msg(x) => // handle msg}

Actor a waits for

...a ! Msg(42)...

Task Ti:

Ti+1

wt executes Ti

.apply(Msg(42))Ti+2:

Page 17: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 17/23

Thread Pool ResizingA suspended inreceive{ case Msg(x) =>... }

B suspendedin library (e.g. wait())

...A ! Msg(x)...

T1: Executing T1 would unblock wt1!

T1

wt1 wt2

Page 18: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 18/23

Implementing Producers (3)

Economize one thread in Producer by changing receive in the coordinator actor to react

val coordinator = actor { loop { react { case Next => react { case x: Option[_] => client ! x } } }}

Page 19: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 19/23

Composing Actors

● Composing event­driven code non­trivial– react may unwind stack at any point– Normal sequencing does not work

● Composition operators for common uses– a andThen b runs a followed by b– def loop(body: => Unit) = body andThen loop(body)

Page 20: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 20/23

Channelstrait OutputChannel[-Msg] { def !(msg: Msg): Unit def forward(msg: Msg): Unit}trait InputChannel[+Msg] { receive[R](f: PartialFunction[Msg, R]): R react(f: PartialFunction[Msg, Unit]): Nothing ...}

class Channel[Msg] extends InputChannel[Msg] with OutputChannel[Msg]

trait Actor extends OutputChannel[Any] { ...}

Page 21: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 21/23

Selective Communication

● Generalize receive/react:receive { case DataCh ! data => ... case CtrlCh ! cmd => ...}

receive { case DataCh ! data => ... case CtrlCh ! cmd => ...} orElse super.reactions

● Composing alternatives using orElse:

Page 22: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 22/23

Experimental ResultsNumber of token passes per second in ring of processes.

Page 23: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 23/23

Conclusion

● Threads and events can be unified under an abstraction of actors

● receive/react allows programmers to trade­off efficiency for flexibility

● Implemented in Scala Actors library (http://www.scala-lang.org/)

● Real­world usage: lift web framework

Page 24: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 24/23

Thread Pool Resizing (2)(cf. SEDA [Welsh01])

● Sample task queue● Add thread when queue length exceeds 

threshold (up to max. number of threads)● Remove thread when idle for specified period of 

time

Page 25: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 25/23

Experimental Results (2)

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

● Compared to Doug Lea's FJTask framework for Java

Page 26: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 26/23

Programming with Events

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 27: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 27/23

val res = evt...

Client Server

Inversion of Control

Page 28: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 28/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 29: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 29/23

val res = evt...

Client Server

Message sends

Blocking­style Code

Page 30: Actors that Unify Threads and Events - EPFLlampphaller/doc/ActorsUnify.pdf · 06/07/07 Philipp Haller – Scala Actors 6/23 Actors Model of concurrent processes introduced by Hewitt

06/07/07 Philipp Haller – Scala Actors 30/23

Concurrency is Indispensable

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

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