Share
Embed
Transcript
84 slides
-
Forward to a Promising Future Kiko Fernandez-Reyes, Dave Clarke, Elias
Castegren and Huu Phuc-Vo Uppsala University, Sweden -
Active object B Active object A Concurrent & Parallel Programming
• Active Objects have existed since mid-80 s = future Abbreviation: active object = actor -
Active object B Active object A Concurrent & Parallel Programming
• Active Objects have existed since mid-80 s = future Abbreviation: active object = actor -
Active object B Active object A Concurrent & Parallel Programming
• Active Objects have existed since mid-80 s Value = future Abbreviation: active object = actor -
Active object B Active object A Concurrent & Parallel Programming
• Active Objects have existed since mid-80 s = future Abbreviation: active object = actor -
Motivation Many computations block on a future to get its
result only to return that result immediately -
Motivation Many computations block on a future to get its
result only to return that result immediately -
Motivation Many computations block on a future to get its
result only to return that result immediately -
Motivation Many computations block on a future to get its
result only to return that result immediately -
1. get 2. await Motivation Many computations block on a
future to get its result only to return that result immediately -
1. get 2. await Motivation Many computations block on a
future to get its result only to return that result immediately -
1. get 2. await Motivation Many computations block on a
future to get its result only to return that result immediately -
1. get 2. await Motivation Many computations block on a
future to get its result only to return that result immediately Interesting for behavioural design patterns: -
1. get 2. await Motivation Many computations block on a
future to get its result only to return that result immediately Interesting for behavioural design patterns: Broker Mediator Chain of responsibility PubSub -
Broker Requesters broker!run( ) new Job(1) active class Broker val
workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) return get(future) end end 2 1 Problem GET Responders -
Broker Requesters broker!run( ) new Job(1) active class Broker val
workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) return get(future) end end 2 1 Problem GET Responders -
Broker Requesters broker!run( ) new Job(1) active class Broker val
workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) return get(future) end end 2 1 Problem GET 1 Responders -
Broker Requesters broker!run( ) new Job(1) active class Broker val
workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) return get(future) end end 2 1 Problem GET 1 Responders -
Broker Requesters broker!run( ) new Job(1) active class Broker val
workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) return get(future) end end 2 1 Problem GET 1 2 Responders -
Broker Requesters broker!run( ) new Job(1) active class Broker val
workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) return get(future) end end 2 1 Problem GET Value 1 2 Responders -
Broker Requesters broker!run( ) new Job(1) active class Broker val
workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) return get(future) end end 2 1 Problem GET 1 2 Responders -
Broker Requesters broker!run( ) new Job(1) active class Broker val
workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) return get(future) end end 2 1 Problem GET 1 2 Responders -
Broker Requesters broker!run( ) new Job(1) active class Broker val
workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) return get(future) end end 2 1 Problem GET 1 2 Responders -
Broker Requesters broker!run( ) new Job(1) Problem Nothing active class
Broker val workers: Buffered[Worker] var current: uint def run(job: Job): Fut int val worker = this.workers[++this.current % workers.size()] return worker!start(job) end end 1 Responders -
Broker Requesters broker!run( ) new Job(1) Problem Nothing active class
Broker val workers: Buffered[Worker] var current: uint def run(job: Job): Fut int val worker = this.workers[++this.current % workers.size()] return worker!start(job) end end 1 Responders -
Broker Requesters broker!run( ) new Job(1) Problem Nothing active class
Broker val workers: Buffered[Worker] var current: uint def run(job: Job): Fut int val worker = this.workers[++this.current % workers.size()] return worker!start(job) end end 1 Responders -
Broker Requesters broker!run( ) new Job(1) Problem Nothing active class
Broker val workers: Buffered[Worker] var current: uint def run(job: Job): Fut int val worker = this.workers[++this.current % workers.size()] return worker!start(job) end end 1 Responders -
Broker Requesters broker!run( ) new Job(1) Problem Nothing active class
Broker val workers: Buffered[Worker] var current: uint def run(job: Job): Fut int val worker = this.workers[++this.current % workers.size()] return worker!start(job) end end 1 Responders 1 -
Broker Requesters broker!run( ) new Job(1) Problem Nothing active class
Broker val workers: Buffered[Worker] var current: uint def run(job: Job): Fut int val worker = this.workers[++this.current % workers.size()] return worker!start(job) end end 1 Responders 1 -
Broker Requesters broker!run( ) new Job(1) Problem AWAIT active class
Broker val workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) await(future) return get(future) end end 2 1 Responders -
Broker Requesters broker!run(new Job(1),p) Problem Promise active class Broker val
workers: Buffered[Worker] var current: uint def run(job: Job, prom: Promise[int]): unit val worker = this.workers[++this.current % workers.size()] worker!start(job, prom) end end 3 Responders let p = new Prom() 1 2 -
Broker Requesters broker!run(new Job(1),p) Problem Promise active class Broker val
workers: Buffered[Worker] var current: uint def run(job: Job, prom: Promise[int]): unit val worker = this.workers[++this.current % workers.size()] worker!start(job, prom) end end 3 Responders let p = new Prom() 1 1 2 -
Broker Requesters broker!run(new Job(1),p) Problem Promise active class Broker val
workers: Buffered[Worker] var current: uint def run(job: Job, prom: Promise[int]): unit val worker = this.workers[++this.current % workers.size()] worker!start(job, prom) end end 3 Responders let p = new Prom() 1 1 2 2 -
Broker Requesters broker!run(new Job(1),p) Problem Promise active class Broker val
workers: Buffered[Worker] var current: uint def run(job: Job, prom: Promise[int]): unit val worker = this.workers[++this.current % workers.size()] worker!start(job, prom) end end 3 Responders let p = new Prom() 1 1 2 2 -
Broker Requesters broker!run(new Job(1),p) Problem Promise active class Broker val
workers: Buffered[Worker] var current: uint def run(job: Job, prom: Promise[int]): unit val worker = this.workers[++this.current % workers.size()] worker!start(job, prom) end end 3 Responders let p = new Prom() 1 1 2 2 3 -
Broker Requesters broker!run(new Job(1),p) Problem Promise active class Broker val
workers: Buffered[Worker] var current: uint def run(job: Job, prom: Promise[int]): unit val worker = this.workers[++this.current % workers.size()] worker!start(job, prom) end end 3 Responders let p = new Prom() 1 1 2 2 3 -
Broker Requesters broker!run(new Job(1),p) Problem Promise active class Broker val
workers: Buffered[Worker] var current: uint def run(job: Job, prom: Promise[int]): unit val worker = this.workers[++this.current % workers.size()] worker!start(job, prom) end end 3 Responders let p = new Prom() 1 1 2 2 3 -
Broker Requesters broker!run(new Job(1),p) Problem Promise active class Broker val
workers: Buffered[Worker] var current: uint def run(job: Job, prom: Promise[int]): unit val worker = this.workers[++this.current % workers.size()] worker!start(job, prom) end end 3 Responders let p = new Prom() 1 1 2 2 Value Value 3 -
Alternatives Comparison Futures Promises Pros Static fulfilment guarantees Flexibility Cons
Rigid No fulfilment guarantees Fulfilled multiple times? -
Main idea • Write future-based code with static fulfilment guarantees
with the flexibility of promises Main idea -
Broker Requesters broker.run( ) new Job(1) Explore Forward Broker broker!run(
) new Job(1) active class Broker val workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) forward(future) end end 1 Responders -
Broker Requesters broker.run( ) new Job(1) Explore Forward Broker broker!run(
) new Job(1) active class Broker val workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) forward(future) end end 1 Responders -
Broker Requesters broker.run( ) new Job(1) Explore Forward Broker broker!run(
) new Job(1) active class Broker val workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) forward(future) end end 1 Responders -
Broker Requesters broker.run( ) new Job(1) Explore Forward Broker broker!run(
) new Job(1) 1 active class Broker val workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) forward(future) end end 1 Responders -
Broker Requesters broker.run( ) new Job(1) Explore Forward Broker broker!run(
) new Job(1) 1 active class Broker val workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) forward(future) end end 1 Responders -
Requesters broker.run( ) new Job(1) Explore Forward Broker broker!run( )
new Job(1) Value Responders forward(x!run(..)) forward(y!run(..)) forward(z!run(..)) -
Requesters broker.run( ) new Job(1) Explore Forward Broker broker!run( )
new Job(1) Value Responders forward(x!run(..)) forward(y!run(..)) forward(z!run(..)) -
Contributions • High-level (future) task-based language • Low-level promise-based language
• Compilation strategy from high- to low-level language (proof that translation is semantics preserving) • Implementation and microbenchmarks The formalisation captures the essence of the implementation -
Typing rules return type of a task • forbids the
use of forward in contexts where the expected task type is not clear closure can be passed between tasks and run in a context different from their defining contexts -
Compilation Strategy • Inductive compilation of: 1. configurations 2. expressions
and values 3. types -
Compilation Strategy Compilation of: • configurations • expressions and values
• types e =future Bisimulation up-to expansion to proof that it is semantics preserving -
Implementation • Encore actor-based language • Compiled from Encore to
C • Microbenchmarks Broker pattern: • get • await + get • forward -
Benchmark Performance (lower is better) Why? Blocking Context switch &
creates more futures -
(lower is better) Benchmark Memory Saves the whole stack on
each context switch Creates more futures than the forwarding version Why? -
More goodies in paper Standard reduction rules Optimised reduction rules
In-depth explanation of bisimulation using a LTS More examples of: • Reduction rules • Compilation strategy • etc -
Conclusion Main idea • Forward fixes: • get-and-return and •
await-get-return Write high-level future-based code & Output low-level promise-based code with static fulfilment guarantees