At Microsofts Professional Developers Conference (PDC) a few years back, we introduced the LINQ project to solve the impedance mismatch between various data models by means of integrated query syntax in mainstream programming languages. Today, we’re seeing a rich ecosystem around LINQ providers that allow developers to reach out to many more data sources. However, there’s a lot of opportunity left to democratize even more data models. Based on the theory of monads, we’ll explore the incredibly powerful nature of query comprehensions to build reactive queries.
Asynchronous, event-driven "reactive" programming is way too hard in today's world of development tools and frameworks. The huge amount of manual and error-prone plumbing leads to incomprehensible and hard to maintain code. As we reach out to services in the cloud, the desire for asynchronous computation is ever increasing, requiring a fresh look on the problems imposed by reactive programming. Centered around the concept of observable data sources, Rx provides a framework that takes care of the hard parts of reactive programming. Instead of focusing on the hard parts, you now can start dreaming about the endless possibilities of composing queries over asynchronous data sources, piggybacking on convenient LINQ syntax.
In this session, we'll cover the design philosophy of Rx, rooted on the deep duality between the interactive IEnumerable interface and the new reactive IObservable interface in .NET 4.
From this core understanding, we'll start looking at various combinators and operators defined over observable collections, as provided by Rx, driving concepts home by a bunch of samples. Finally, if time permits, we'll look at the Reactive Extensions for JavaScript which allows us to take the concepts we already know from Rx and apply them to JavaScript and have deep integration with libraries such as jQuery. Democratizing asynchronous programming starts today. Don't miss out on it!
Unraveling Multimodality with Large Language Models.pdf
Rx: Curing Your Asynchronous Programming Blues | QCon London
1. Rx:
Curing
your
Asynchronous
Programming
Blues
Bart
J.F.
De
Smet
Microso'
Corpora,on
bartde@microso'.com
2. Why
Should
I
Care?
GPS
RSS
feeds
Stock
,ckers
Social
media
Server
management
3. Mission
Statement
Too
hard
today!
(! ◦ ")(#) = !("(#))
Rx is a library for composing
asynchronous and event-based
programs using observable
sequences.
Queries?
LINQ?
• .NET
3.5
SP1
and
4.0
• Silverlight
3
and
4
• XNA
3.1
for
XBOX
and
Zune
• Windows
Phone
7
• JavaScript
(RxJS)
MSDN
Data
Developer
Center
NuGet
4. Essen,al
Interfaces
interface
IEnumerable<out
T>
{
IEnumerator<T>
GetEnumerator();
}
C# 4.0 covariance
interface
IEnumerator<out
T>
:
IDisposable
{
You could get
bool
MoveNext();
stuck
T
Current
{
get;
}
void
Reset();
}
5. Essen,al
Interfaces
(WaiHng
to
move
next)
C# 4.0 covariance
moving
on
You could get
stuck
6. Mathema,cal
Duality
Because
the
Dutch
are
(said
to
be)
cheap
– Electricity:
inductor
and
capacitor
– Logic:
De
Morgan’s
Law
¬(%∧&)≡¬%∨¬&
¬(%∨&)≡¬%∧¬&
– Programming?
7. What’s
the
dual
of
IEnumerable?
The
recipe
to
dualiza,on
h^p://en.wikipedia.org/wiki/Dual_(category_theory)
Reversing arrows…
Input becomes output and vice
versa
Making
a
U-‐turn
in
synchrony
8. What’s
the
dual
of
IEnumerable?
interface
IEnumerable<out
T>
{
IEnumerator<T>
GetEnumerator();
}
interface
IEnumerator<out
T>
:
IDisposable
{
bool
MoveNext();
T
Current
{
get;
}
Properties
void
Reset();
are methods
}
9. What’s
the
dual
of
IEnumerable?
interface
IEnumerable<out
T>
{
IEnumerator<T>
GetEnumerator();
}
interface
IEnumerator<out
T>
:
IDisposable
{
bool
MoveNext();
T
GetCurrent();
void
Reset();
A historical mishap
}
10. What’s
the
dual
of
IEnumerable?
interface
IEnumerable<out
T>
{
IEnumerator<T>
GetEnumerator();
}
interface
IEnumerator<out
T>
:
IDisposable
{
bool
MoveNext();
No checked
T
GetCurrent();
exceptions in .NET /
C#
}
11. What’s
the
dual
of
IEnumerable?
interface
IEnumerable<out
T>
{
IEnumerator<T>
GetEnumerator();
}
interface
IEnumerator<out
T>
:
IDisposable
{
bool
MoveNext()
throws
Exception;
T
GetCurrent();
}
12. What’s
the
dual
of
IEnumerable?
interface
IEnumerable<out
T>
{
IEnumerator<T>
GetEnumerator();
}
interface
IEnumerator<out
T>
:
IDisposable
{
bool
MoveNext()
throws
Exception;
T
GetCurrent();
This is an
}
output too!
13. What’s
the
dual
of
IEnumerable?
interface
IEnumerable<out
T>
{
IEnumerator<T>
GetEnumerator();
}
interface
IEnumerator<out
T>
:
IDisposable
{
(bool
|
Exception)
MoveNext();
T
GetCurrent();
Discriminated
union
}
Really only two type
(“or”)
values
18. What’s
the
dual
of
IEnumerable?
interface
IEnumerable<out
T>
{
(IEnumerator<T>
&
IDisposable)
GetEnumerator();
}
Variance will flip!
interface
IEnumerator<out
T>
{
(T
|
void
|
Exception)
MoveNext();
}
Will rename too This is really void
19. What’s
the
dual
of
IEnumerable?
interface
IEnumerable<out
T>
{
(IEnumerator<T>
&
IDisposable)
GetEnumerator();
}
interface
IEnumeratorDual<in
T>
{
void
OnNext(T
|
void
|
Exception);
}
Can encode as
three methods
20. What’s
the
dual
of
IEnumerable?
interface
IEnumerable<out
T>
{
(IEnumerator<T>
&
IDisposable)
GetEnumerator();
}
interface
IEnumeratorDual<in
T>
{
Color of the
void
OnNext(T
value);
bikeshed (*)
void
OnCompleted();
void
OnError(Exception
exception);
}
(*)
Visit
h^p://en.wikipedia.org/wiki/Color_of_the_bikeshed
21. What’s
the
dual
of
IEnumerable?
Will leave this
interface
IEnumerable<out
T>
part alone
{
(IEnumerator<T>
&
IDisposable)
GetEnumerator();
}
This is the data
source Need to patch
interface
IObserver<in
T>
this one up too
{
void
OnNext(T
value);
void
OnCompleted();
void
OnError(Exception
exception);
}
22. What’s
the
dual
of
IEnumerable?
Color of the
interface
IEnumerableDual<out
T>
bikeshed (*)
{
IDisposable
SetObserver(IObserver<T>
observer);
}
interface
IObserver<in
T>
{
void
OnNext(T
value);
void
OnCompleted();
void
OnError(Exception
exception);
}
(*)
Visit
h^p://en.wikipedia.org/wiki/Color_of_the_bikeshed
29. Geeng
Your
Observables
A variant with time notion Hypothetical anonymous
exists (GenerateWithTime) iterator syntax in C#
o
=
Observable.Generate(
new IEnumerable int
0,
for int
i
=>
i
<
10,
i
=>
i
+
1,
i
=>
i
*
i
yield
return
);
Asynchronou
Synchronous
s
o.Subscribe(x
=>
{
foreach var in
Console.WriteLine(x);
Console
});
30. Geeng
Your
Observables
IObservable<int>
o
=
Observable.Create<int>(observer
=>
{
//
Assume
we
introduce
concurrency
(see
later)…
observer.OnNext(42);
observer.OnCompleted();
return
()
=>
{
/*
unsubscribe
action
*/
};
});
IDisposable
subscription
=
o.Subscribe(
onNext:
x
=>
{
Console.WriteLine("Next:
"
+
x);
},
onError:
ex
=>
{
Console.WriteLine("Oops:
"
+
ex);
},
onCompleted:
()
=>
{
Console.WriteLine("Done");
}
);
C# doesn’t have anonymous interface
C# 4.0 named implementation, so we provide various
parameter syntax extension methods that take lambdas.
31. Geeng
Your
Observables
IObservable<int>
o
=
Observable.Create<int>(observer
=>
{
//
Assume
we
introduce
concurrency
(see
later)…
observer.OnNext(42);
observer.OnCompleted();
return
()
=>
{
/*
unsubscribe
action
*/
};
});
IDisposable
subscription
=
o.Subscribe(
onNext:
x
=>
{
Console.WriteLine("Next:
"
+
x);
},
onError:
ex
=>
{
Console.WriteLine("Oops:
"
+
ex);
},
onCompleted:
()
=>
{
Console.WriteLine("Done");
}
);
Thread.Sleep(30000);
//
Main
thread
is
blocked…
F10
32. Geeng
Your
Observables
IObservable<int>
o
=
Observable.Create<int>(observer
=>
{
//
Assume
we
introduce
concurrency
(see
later)…
observer.OnNext(42);
observer.OnCompleted();
return
()
=>
{
/*
unsubscribe
action
*/
};
});
IDisposable
subscription
=
o.Subscribe(
onNext:
x
=>
{
Console.WriteLine("Next:
"
+
x);
},
onError:
ex
=>
{
Console.WriteLine("Oops:
"
+
ex);
},
onCompleted:
()
=>
{
Console.WriteLine("Done");
}
);
Thread.Sleep(30000);
//
Main
thread
is
blocked…
F10
33. Geeng
Your
Observables
IObservable<int>
o
=
Observable.Create<int>(observer
=>
{
//
Assume
we
introduce
concurrency
(see
later)…
observer.OnNext(42);
observer.OnCompleted();
return
()
=>
{
/*
unsubscribe
action
*/
};
});
IDisposable
subscription
=
o.Subscribe(
onNext:
x
=>
{
Console.WriteLine("Next:
"
+
x);
},
onError:
ex
=>
{
Console.WriteLine("Oops:
"
+
ex);
},
onCompleted:
()
=>
{
Console.WriteLine("Done");
}
);
Thread.Sleep(30000);
//
Main
thread
is
blocked…
F5
34. Geeng
Your
Observables
IObservable<int>
o
=
Observable.Create<int>(observer
=>
{
//
Assume
we
introduce
concurrency
(see
later)…
observer.OnNext(42);
observer.OnCompleted();
return
()
=>
{
/*
unsubscribe
action
*/
};
});
Breakpoint
got hit
IDisposable
subscription
=
o.Subscribe(
onNext:
x
=>
{
Console.WriteLine("Next:
"
+
x);
},
onError:
ex
=>
{
Console.WriteLine("Oops:
"
+
ex);
},
onCompleted:
()
=>
{
Console.WriteLine("Done");
}
);
Thread.Sleep(30000);
//
Main
thread
is
blocked…
36. Bridging
Rx
with
the
World
How to pass around? Hidden data source
form1.MouseMove += (sender, args) => {
if (args.Location.X == args.Location.Y)
// I’d like to raise another event
};
Lack of composition
form1.MouseMove -= /* what goes here? */
Resource
maintenance?
37.
38. Bridging
Rx
with
the
World
Source of Point
Objects can be passed
values
IObservable<Point> mouseMoves =
Observable.FromEvent(frm, "MouseMove");
var filtered = mouseMoves
.Where(pos => pos.X == pos.Y);
Can define operators
var subscription = filtered.Subscribe(…);
subscription.Dispose();
Resource
maintenance!
39. Bridging
Rx
with
the
World
Exceptions? Hidden data source
FileStream
fs
=
File.OpenRead("data.txt");
byte[]
bs
=
new
byte[1024];
fs.BeginRead(bs,
0,
bs.Length,
Really a method pair
new
AsyncCallback(iar
=>
{
int
bytesRead
=
fs.EndRead(iar);
Cancel?
//
Do
something
with
bs[0..bytesRead-‐1]
}),
null
Lack of composition
);
Synchronous
State? completion?
40. Bridging
Rx
with
the
World
FileStream
fs
=
File.OpenRead("data.txt");
Func<byte[],
int,
int,
IObservable<int>>
read
=
Observable.FromAsyncPattern<byte[],
int,
int,
int>(
fs.BeginRead,
fs.EndRead);
byte[]
bs
=
new
byte[1024];
read(bs,
0,
bs.Length).Subscribe(bytesRead
=>
{
//
Do
something
with
bs[0..bytesRead-‐1]
});
Tip: a nicer wrapper can easily be
made using various operators
41. Bridging
Rx
with
the
World
don’t
replace
unify
composiHonality
generic operators
build
bridges!
42. Bridging
Rx
with
the
World
• Cold
observables
var
Observable.Return
Triggered by subscription
.Subscribe( ) //
Prints
42
.Subscribe( ) //
Prints
42
again
• Hot
observables
var Observable.FromEvent MouseEventArgs
"MouseMove"
Mouse events going
before subscription
Console
44. Composi,on
and
Querying
Parameterization
IScheduler
of operators
var .Return Scheduler.ThreadPool
Console
Will run on the
source’s scheduler
45. Composi,on
and
Querying
duality
– Convert
between
both
worlds
//
Introduces
concurrency
to
enumerate
and
signal…
var .ToObservable();
//
Removes
concurrency
by
observing
and
yielding…
var .ToEnumerable()
• “Time-‐centric”
reacHve
operators:
Race!
.Amb( )
47. Composi,on
and
Querying
• Observables
are
sources
of
data
– Data
is
sent
to
you
(push
based)
– Extra
(op,onal)
noHon
of
Hme
• Hence
we
can
query
over
them
//
Producing
an
IObservable<Point>
using
Select
var
mme
=
from
mm
in
Observable.FromEvent<MouseEventArgs>(
form,
“MouseMove”)
select
mm.EventArgs.Location;
//
Filtering
for
the
first
bisector
using
Where
var
res
=
from
mm
in
mme
where
mm.X
==
mm.Y
select
mm;
48. Composi,on
and
Querying
Asynchronou
s request
IObservable<string>
TextChanged
React Dictionary
web service
Reaction
Reactive
Reactor
IObservable<DictionaryWord[]>
Data binding
on UI thread
49. Composi,on
and
Querying
//
IObservable<string>
from
TextChanged
events
var
changed
=
Observable.FromEvent<EventArgs>(txt,
"TextChanged");
var
input
=
(from
text
in
changed
select
((TextBox)text.Sender).Text);
.DistinctUntilChanged()
.Throttle(TimeSpan.FromSeconds(1));
//
Bridge
with
the
dictionary
web
service
var
svc
=
new
DictServiceSoapClient();
var
lookup
=
Observable.FromAsyncPattern<string,
DictionaryWord[]>
(svc.BeginLookup,
svc.EndLookup);
//
Compose
both
sources
using
SelectMany
var
res
=
from
term
in
input
input.SelectMany(term
=>
from
words
in
lookup(term)
lookup(term))
select
words;
51. Composi,on
and
Querying
Reactive|
Reacti|
React|
Reac|
Rea|
Re|
|
Reactiv|
R| input
Reactive
Reaction
Reactive Service
call
1
Reactor
Service
call
2
UI
data
binding
Source: http://scrapetv.com
52. Composi,on
and
Querying
Reactive|
Reacti|
React|
Reac|
Rea|
Re|
|
Reactiv|
R| input
UnHl
Reactive
Service
call
1
Take
Service
call
2
UI
data
binding
53. Composi,on
and
Querying
//
IObservable<string>
from
TextChanged
events
var
changed
=
Observable.FromEvent<EventArgs>(txt,
"TextChanged");
var
input
=
(from
text
in
changed
select
((TextBox)text.Sender).Text);
.DistinctUntilChanged()
.Throttle(TimeSpan.FromSeconds(1));
//
Bridge
with
the
dictionary
web
service
var
svc
=
new
DictServiceSoapClient();
var
lookup
=
Observable.FromAsyncPattern<string,
DictionaryWord[]>
(svc.BeginLookup,
svc.EndLookup);
Very local fix
//
Compose
both
sources
using
SelectMany
J
var
res
=
from
term
in
input
from
words
in
lookup(term).TakeUntil(input)
select
words;
54. Composi,on
and
Querying
//
IObservable<string>
from
TextChanged
events
var
changed
=
Observable.FromEvent<EventArgs>(txt,
"TextChanged");
var
input
=
(from
text
in
changed
select
((TextBox)text.Sender).Text);
.DistinctUntilChanged()
.Throttle(TimeSpan.FromSeconds(1));
//
Bridge
with
the
dictionary
web
service
var
svc
=
new
DictServiceSoapClient();
var
lookup
=
Observable.FromAsyncPattern<string,
DictionaryWord[]>
(svc.BeginLookup,
svc.EndLookup);
//
Alternative
approach
for
composition
using:
//
IObservable<T>
Switch<T>(IObservable<IObservable<T>>
sources)
var
res
=
(from
term
in
input
Hops from source
select
lookup(term)).Switch();
to source
56. Mission
Accomplished
Way
simpler
with
Rx
(! ◦ ")(#) = !("(#))
Rx is a library for composing
asynchronous and event-based
programs using observable
sequences.
Queries!
LINQ!
• .NET
3.5
SP1
and
4.0
• Silverlight
3
and
4
• XNA
3.1
for
XBOX
and
Zune
• Windows
Phone
7
• JavaScript
(RxJS)
MSDN
Data
Developer
Center
NuGet
57. Related
Content
• Hands-‐on
Labs
– Two
flavors:
• Curing
the
asynchronous
blues
with
the
Reac,ve
Extensions
(Rx)
for
.NET
• Curing
the
asynchronous
blues
with
the
Reac,ve
Extensions
(Rx)
for
JavaScript
– Both
can
be
found
via
the
Rx
forums
• Rx
team
web
presence
– Rx
team
blog
–
h^p://blogs.msdn.com/rxteam
– DevLabs
–
h^p://msdn.microso'.com/en-‐us/devlabs/ee794896.aspx
– MSDN
forums
–
h^p://social.msdn.microso'.com/Forums/en-‐US/rx
– Channel9
–
h^p://channel9.msdn.com/Tags/Rx