async patterns
or how I learned to stop worrying & love the timer
The Problem
user interfaces are async
javascript rich-apps
swing, flex, java applets
operating systems are async
files, memory, cpu
concurrent systems are async
akka, hadoop, elastic
async is hard
when something is executed asynchronously
you lose control over time & execution:
you can't control when your code gets called
you can't control how your code gets called
The Solution
async event handlers
register some work for some remote action
the work will be done when the event happens
....
or maybe not
callbacks
continually passing around the rest of the work
a simple callback
def onUserClick(event) { // call me maybe
event.getUser().sendGreeting();
}
async.register("user-click", onUserClick);
def onUserClick(event) { // call me maybe
event.getUser().sendGreeting();
}
async.register("user-click", onUserClick);
there's some work to be done
we'll register it to happen on user click
what if looking up the user was asynchronous?
def onUserClick(event) {
def onUserFound(user) {
user.sendGreeting();
};
async.register("find-user", onUserFound);
}
async.register("user-click", onUserClick);
"continuation passing style"
also known as the pyramid of doom
async version of russian nesting dolls
callback hell
saveKingdom(function(kingdom) {
kingdom.fightBattle(function(battle) {
battle.getMessage(function(message) {
message.getRider(function(rider) {
rider.getHorse(function(horse) {
horse.getShoe(function(shoe) {
shoe.getNail(function(nail) {
saveTheKingdom();
});
});
});
});
});
});
}); => // RuntimeException: NailNotFound
and all for the want of a horseshoe nail
beware callbacks
/\
___ / \ ___ / \ __ / \ __ / / \ / \ _ / <()> \ _ / \ / \_/ \_/ \_/________\_/ \_/ \_/ __________________/__I___I___\________________ /_I___I___I__\ /I___I___I___I_\ /___I___I___I___I\ /__I___I___I___I___\ /_I___I___I___I___I__\ /I___I___I___I___I___I_\ /___I___I___I___I___I___I\ /__I___I___I___I___I___I___\ /_I___I___I___I___I___I___I__\
promises
if it happens, we'll let you know
the promise
something might happen
(the promise was fulfilled)
or it might not happen
(the promise was rejected)
the interface
promise.then(onFulfilled, onRejected);
only one will be called
someone else decides which
async composition
promises beget more promises
loginRequest.then(function(user) {
return user.authenticate(); // => AuthenticatedUser
}).then(function(authedUser) {
authedUser.useSystem();
});
fulfill promises by getting your work done
promises make async programming easier
un-invert the inversion of control
gain time independence
organize work into isolated units instead of nesting
code in isolation is easier to test
explicitly recognize non-determinism with logical branching (reject/fulfill)
...
async programming is still hard
promises are contageous
in order to compose promises you must return promises
promises are single use
can only be fulfilled or rejected once
cannot represent continuous streams of events, like user input
promises offer a powerful way to coordinate discrete events
reactive extensions
collection oriented async
Observerables & Subscriptions
observables are async event channels
discrete messages flow through the channels
subscriptions provide a way to tap into the stream
broadcast messaging provides any number of listeners to event sources
Rx provides stream collection operations
map to transform streams
filter to select particular messages
reduce to scan messages over time
each operation returns a new observable
turn async events emitters into observable workflows
rx : eventStreams :: promises : asyncEvents
reactive programming makes async powerful
keys = rx.observable("keypress");
enter = keys.filter(function(key) {
return key == ENTER_CODE;
});
enter.subscribe(doWork);
pretend event streams are just simple array-likes
messy async code is simple
just put a message on a stream
RxJava
by netflix
getStringsFromNetwork()
.skip(10) // who cares about the first ten messages .take(5) // i only want five messages .map({ s -> return(s + "_transformed"); }) .subscribe({ it -> println("onNext => " + it); });
more examples
- bacon.js
- storm
- core.async
- RxJs
- LINQ
async programming is still hard
callbacks pyramids, actors, promises,
goroutines, reactive,
race conditions,
oh my...
no silver bullet
no solution is right for every problem
when you have a favorite hammer, everything starts looking like a nail
programming is a way to help us think about problems
only use patterns when they make things easier to understand
Principles of Reactive Programming
fundamentals of concurrency and async using reactive programming, taught in Scala by the author, Martin Odersky exploring Reactive Extensions, by the creator Erik Meijer.
Free course starts Nov 4th 2013 and runs for 7 weeks
happy coding
- tomans
async patterns
By Thomas Omans
async patterns
- 2,582