SlideShare a Scribd company logo
Asynchronous Application
Patterns in C#
Frank A. Krueger
@praeclarum
Async
How C# Makes Every Other Language Look Stupid
Frank A. Krueger
@praeclarum
Why Async?
Why Await?
Tour of System.Threading.Tasks
with Real-world Uses of Await
Fak-world Uses of Await
Why Async?
Why Await?
Tour of System.Threading.Tasks
with Real-world Uses of Await
Fak-world Uses of Await
Apps are Async
• Interacting with the user
• Performing computations
• Downloading resources from the web
• Uploading actions and messages to services
• Reading and writing local storage
• Watching for motion changes, camera or
microphone events, network connectivity,
etc.
http://xamarin.com/evolve/2013
http://xamarin.com/evolve/2013
You can’t do anything!
http://calca.io
And So Async...
• .NET Events
• .NET 1.0 Async (IAsyncResult)
And So Async...
• .NET Events
• .NET 1.0 Async (IAsyncResult)
• Closures! Continuation Passing Style FTW!
And So Async...
• .NET Events
• .NET 1.0 Async (IAsyncResult)
• Closures! Continuation Passing Style FTW!
• IObservable<T>
And So Async...
• .NET Events
• .NET 1.0 Async (IAsyncResult)
• Closures! Continuation Passing Style FTW!
• IObservable<T>
ARVIS
And So Async...
• .NET Events
• .NET 1.0 Async (IAsyncResult)
• Closures! Continuation Passing Style FTW!
• IObservable<T>
Asynchronous Retrieval of
Values from Infinite Streams
And So Async...
• .NET Events
• .NET 1.0 Async (IAsyncResult)
• Closures! Continuation Passing Style FTW!
• IObservable<T>
• iOS Delegates
And So Async...
• .NET Events
• .NET 1.0 Async (IAsyncResult)
• Closures! Continuation Passing Style FTW!
• IObservable<T>
• iOS Delegates
• iOS Callbacks (Obj-C bocks)
And So Async...
• .NET Events
• .NET 1.0 Async (IAsyncResult)
• Closures! Continuation Passing Style FTW!
• IObservable<T>
• iOS Delegates
• iOS Callbacks (Obj-C bocks)
• Android Listeners, Event Interfaces
Why Async?
Why Await?
Tour of System.Threading.Tasks
with Real-world Uses of Await
Fak-world Uses of Await
hugMeanPeopleButton.TouchUpInside += delegate {
// Network IO
var tweets = twitterClient.GetMentions ();
// Computation
var q = from t tweets
where t.IsMean
select t;
// Lots of Network IO
foreach (var enemy in q) {
twitterClient.Reply (enemy, “Here’s a hug”);
}
// UI
statusLabel.Text =
string.Join (“, “, q.Select (x => x.Name)) +
“ have been hugged”;
};
©®™ 2013 Krueger Systems, Inc. All Rights Reserved.
hugMeanPeopleButton.TouchUpInside += delegate {
// Network IO
var tweets = twitterClient.GetMentions ();
// Computation
var q = from t tweets
where t.IsMean
select t;
// Lots of Network IO
foreach (var enemy in q) {
twitterClient.Reply (enemy, “Here’s a hug”);
}
// UI
statusLabel.Text =
string.Join (“, “, q.Select (x => x.Name)) +
“ have been hugged”;
};
Slow
Slow x N
Slow?
hugMeanPeopleButton.TouchUpInside += delegate {
// Network IO
twitterClient.GetMentions (
(tweets, tweetsError) => {
if (tweetsError != null)
Umm (tweetsError);
// Computation
var q = from t in tweets
where t.IsMean
select t;
// This is a loop, believe it or not
tweetsToHug = q.ToList ();
nextTweetToHug = 0;
HugTweet ();
});
}
List<Tweet> tweetsToHug = null;
int nextTweetToHug = 0;
void HugTweet ()
{
if (tweetsToHug == null) return;
// Lots of Network IO
if (nextTweetToHug < tweetsToHug.Count) {
var t = tweetsToHug [nextTweetToHug++];
twitterClient.Reply (
t,
“Here’s a hug”,
replyError => {
if (replyError != null)
Umm (replyError);
HugTweet ();
});
return;
}
// UI
statusLabel.Text =
string.Join (“, “,tweetsToHug.Select(x=>x.Name))
+ “ have been hugged”;
tweetsToHug = null;
}
Continuation Passing Style
(CPS)
hugMeanPeopleButton.TouchUpInside += delegate {
// Network IO
twitterClient.GetMentions (
(tweets, tweetsError) => {
if (tweetsError != null)
Umm (tweetsError);
// Computation
var q = from t in tweets
where t.IsMean
select t;
// This is a loop, believe it or not
tweetsToHug = q.ToList ();
nextTweetToHug = 0;
HugTweet ();
});
}
List<Tweet> tweetsToHug = null;
int nextTweetToHug = 0;
void HugTweet ()
{
if (tweetsToHug == null) return;
// Lots of Network IO
if (nextTweetToHug < tweetsToHug.Count) {
var t = tweetsToHug [nextTweetToHug++];
twitterClient.Reply (
t,
“Here’s a hug”,
replyError => {
if (replyError != null)
Umm (replyError);
HugTweet ();
});
return;
}
// UI
statusLabel.Text =
string.Join (“, “,tweetsToHug.Select(x=>x.Name))
+ “ have been hugged”;
tweetsToHug = null;
}
2 Functions?
hugMeanPeopleButton.TouchUpInside += delegate {
// Network IO
twitterClient.GetMentions (
(tweets, tweetsError) => {
if (tweetsError != null)
Umm (tweetsError);
// Computation
var q = from t in tweets
where t.IsMean
select t;
// This is a loop, believe it or not
tweetsToHug = q.ToList ();
nextTweetToHug = 0;
HugTweet ();
});
}
List<Tweet> tweetsToHug = null;
int nextTweetToHug = 0;
void HugTweet ()
{
if (tweetsToHug == null) return;
// Lots of Network IO
if (nextTweetToHug < tweetsToHug.Count) {
var t = tweetsToHug [nextTweetToHug++];
twitterClient.Reply (
t,
“Here’s a hug”,
replyError => {
if (replyError != null)
Umm (replyError);
HugTweet ();
});
return;
}
// UI
statusLabel.Text =
string.Join (“, “,tweetsToHug.Select(x=>x.Name))
+ “ have been hugged”;
tweetsToHug = null;
}
StateVariables?
hugMeanPeopleButton.TouchUpInside += delegate {
// Network IO
twitterClient.GetMentions (
(tweets, tweetsError) => {
if (tweetsError != null)
Umm (tweetsError);
// Computation
var q = from t in tweets
where t.IsMean
select t;
// This is a loop, believe it or not
tweetsToHug = q.ToList ();
nextTweetToHug = 0;
HugTweet ();
});
}
List<Tweet> tweetsToHug = null;
int nextTweetToHug = 0;
void HugTweet ()
{
if (tweetsToHug == null) return;
// Lots of Network IO
if (nextTweetToHug < tweetsToHug.Count) {
var t = tweetsToHug [nextTweetToHug++];
twitterClient.Reply (
t,
“Here’s a hug”,
replyError => {
if (replyError != null)
Umm (replyError);
HugTweet ();
});
return;
}
// UI
statusLabel.Text =
string.Join (“, “,tweetsToHug.Select(x=>x.Name))
+ “ have been hugged”;
tweetsToHug = null;
}
Subtle but Critical
Assignments?
hugMeanPeopleButton.TouchUpInside += delegate {
// Network IO
twitterClient.GetMentions (
(tweets, tweetsError) => {
if (tweetsError != null)
Umm (tweetsError);
// Computation
var q = from t in tweets
where t.IsMean
select t;
// This is a loop, believe it or not
tweetsToHug = q.ToList ();
nextTweetToHug = 0;
HugTweet ();
});
}
List<Tweet> tweetsToHug = null;
int nextTweetToHug = 0;
void HugTweet ()
{
if (tweetsToHug == null) return;
// Lots of Network IO
if (nextTweetToHug < tweetsToHug.Count) {
var t = tweetsToHug [nextTweetToHug++];
twitterClient.Reply (
t,
“Here’s a hug”,
replyError => {
if (replyError != null)
Umm (replyError);
HugTweet ();
});
return;
}
// UI
statusLabel.Text =
string.Join (“, “,tweetsToHug.Select(x=>x.Name))
+ “ have been hugged”;
tweetsToHug = null;
}
Recursion?
hugMeanPeopleButton.TouchUpInside += delegate {
// Network IO
twitterClient.GetMentions (
(tweets, tweetsError) => {
if (tweetsError != null)
Umm (tweetsError);
// Computation
var q = from t in tweets
where t.IsMean
select t;
// This is a loop, believe it or not
tweetsToHug = q.ToList ();
nextTweetToHug = 0;
HugTweet ();
});
}
List<Tweet> tweetsToHug = null;
int nextTweetToHug = 0;
void HugTweet ()
{
if (tweetsToHug == null) return;
// Lots of Network IO
if (nextTweetToHug < tweetsToHug.Count) {
var t = tweetsToHug [nextTweetToHug++];
twitterClient.Reply (
t,
“Here’s a hug”,
replyError => {
if (replyError != null)
Umm (replyError);
HugTweet ();
});
return;
}
// UI
statusLabel.Text =
string.Join (“, “,tweetsToHug.Select(x=>x.Name))
+ “ have been hugged”;
tweetsToHug = null;
}
Tail End of Process in a
Strange Function?
hugMeanPeopleButton.TouchUpInside += delegate {
// Network IO
twitterClient.GetMentions (
(tweets, tweetsError) => {
if (tweetsError != null)
Umm (tweetsError);
// Computation
var q = from t in tweets
where t.IsMean
select t;
// This is a loop, believe it or not
tweetsToHug = q.ToList ();
nextTweetToHug = 0;
HugTweet ();
});
}
List<Tweet> tweetsToHug = null;
int nextTweetToHug = 0;
void HugTweet ()
{
if (tweetsToHug == null) return;
// Lots of Network IO
if (nextTweetToHug < tweetsToHug.Count) {
var t = tweetsToHug [nextTweetToHug++];
twitterClient.Reply (
t,
“Here’s a hug”,
replyError => {
if (replyError != null)
Umm (replyError);
HugTweet ();
});
return;
}
// UI
statusLabel.Text =
string.Join (“, “,tweetsToHug.Select(x=>x.Name))
+ “ have been hugged”;
tweetsToHug = null;
}
Umm...
Our Languages
Were Not Designed for
Asynchronous Procedures
http://xamarin.com/evolve/2013
http://channel9.msdn.com/Events/Build/BUILD2011/TOOL-816T
Oh, that Anders...
hugMeanPeopleButton.TouchUpInside += delegate {
// Network IO
var tweets = twitterClient.GetMentions ();
// Computation
var q = from t tweets
where t.IsMean
select t;
// Lots of Network IO
foreach (var enemy in q) {
twitterClient.Reply (t, “Here’s a hug”);
}
// UI
statusLabel.Text =
string.Join (“, “, q.Select (x => x.Name)) +
“ have been hugged”;
};
hugMeanPeopleButton.TouchUpInside += async delegate {
// Network IO
var tweets = await twitterClient.GetMentionsAsync ();
// Computation
var q = from t tweets
where t.IsMean
select t;
// Lots of Network IO
foreach (var enemy in q) {
await twitterClient.ReplyAsync (t, “Here’s a hug”);
}
// UI
statusLabel.Text =
string.Join (“, “, q.Select (x => x.Name)) +
“ have been hugged”;
};
hugMeanPeopleButton.TouchUpInside += async delegate {
// Network IO
var tweets = await twitterClient.GetMentionsAsync ();
// Computation
var q = from t tweets
where t.IsMean
select t;
// Lots of Network IO
foreach (var enemy in q) {
await twitterClient.ReplyAsync (t, “Here’s a hug”);
}
// UI
statusLabel.Text =
string.Join (“, “, q.Select (x => x.Name)) +
“ have been hugged”;
};
hugMeanPeopleButton.TouchUpInside += async delegate {
// Network IO
var tweets = await twitterClient.GetMentionsAsync ();
// Computation, in the Background, dood
var q = await Task.Run (() =>
from t tweets
where t.IsMean
select t);
// Lots of Network IO
foreach (var enemy in q) {
await twitterClient.ReplyAsync (t, “Here’s a hug”);
}
// UI
statusLabel.Text =
string.Join (“, “, q.Select (x => x.Name)) +
“ have been hugged”;
};
C#
is Designed for
Asynchronous Procedures
Why Async?
Why Await?
Tour of System.Threading.Tasks
with Real-world Uses of Await
Fak-world Uses of Await
Task
TaskCompletionSource
TaskScheduler
CancellationToken
System.Threading.Task
Parallel Process
await task; // Async
task.Wait (); // Synchronous
System.Threading.Task
Fallible Parallel Process
try {
await task; // Async
task.Wait (); // Synchronous
}
catch (Exception) {
}
System.Threading.Task<T>
Parallel Process
That Returns aValue
var value = await task; // Async
task.Wait (); // Synchronous
var value = task.Result;
Where do Tasks come from?
var tweets = await client.GetTweetsAsync ();
await client.PostAsync (“Hello, World!”);
Call an Async Method
var tweets = await client.GetTweetsAsync ();
await client.PostAsync (“Hello, World!”);
Call an Async Method
Network? CPU? UI?
var value = await Task.Run (() => {
return 42;
});
await Task.Run (() => {
LaunchMissiles ();
});
Start a Background Task
Using a Function
mesh = sphere.Tesselate (opts);
mesh = await Task.Run (() =>
sphere.Tesselate (opts));
async Task<int> GetPopularityAsync ()
{
var followers = await
twitter.GetFollowersAsync ();
return followers.Sum (
x => x.FollowerCount);
}
Methods That Use await
Return Tasks
var value = await Task.Factory.FromAsync (
foo.BeginDoingSomething,
foo.EndDoingSomething,
null);
From .NET 1.0 Async
await Task.Factory.ContinueWhenAll (
downloadTasks,
ts => {});
Combinators
await Task.Factory.ContinueWhenAny (
actionStartGestures,
t => {});
await Task.Factory.ContinueWhenAll (
downloadTasks,
ts => {});
Combinators
await Task.Factory.ContinueWhenAny (
actionStartGestures,
t => {});
Take Multiple Tasks and turn them
into One Task
async Task UpdatePodcasts ()
{
ShowUpdatingUI ();
foreach (var feed in feeds) {
await feed.Update ();
}
ShowUpdatingCompletedUI ();
}
Concurrency?
async Task UpdatePodcasts ()
{
ShowUpdatingUI ();
foreach (var feed in feeds) {
await feed.Update ();
}
ShowUpdatingCompletedUI ();
}
Concurrency?
Sequential
async Task UpdatePodcasts ()
{
ShowUpdatingUI ();
Task.Factory.ContinueWhenAll (
feeds.Select (x => x.Update ()),
null);
ShowUpdatingCompletedUI ();
}
Concurrency!
Parallel
Task
TaskCompletionSource
TaskScheduler
CancellationToken
TaskCompletionSource<T>
Create tasks
whose execution and
termination you control
TaskCompletionSource<T>
Great way to interact with
ancient, old, fuddy duddy,
outdated async models
TaskCompletionSource<T>
tcs.Task
tcs.SetResult ()
tcs.SetException ()
tcs.SetCanceled ()
Task<int> GetAnswerAsync ()
{
var tcs = new TaskCompletionSource<int> ();
ThreadPool.QueueUserWorkItem (() => {
BuildAComputer ();
LetItRun ();
tcs.SetResult (42); // Terminate
});
return tcs.Task;
}
Task<int> GetAnswerAsync ()
{
var tcs = new TaskCompletionSource<int> ();
ThreadPool.QueueUserWorkItem (() => {
BuildAComputer ();
LetItRun ();
tcs.SetResult (42); // Terminate
});
return tcs.Task;
}
Task<int> GetAnswerAsync ()
{
var tcs = new TaskCompletionSource<int> ();
ThreadPool.QueueUserWorkItem (() => {
BuildAComputer ();
LetItRun ();
tcs.SetResult (42); // Terminate
});
return tcs.Task;
}
Task<int> GetAnswerAsync ()
{
var tcs = new TaskCompletionSource<int> ();
ThreadPool.QueueUserWorkItem (() => {
BuildAComputer ();
LetItRun ();
tcs.SetResult (42); // Terminate
});
return tcs.Task;
}
Task<int> GetAnswerAsync ()
{
var tcs = new TaskCompletionSource<int> ();
ThreadPool.QueueUserWorkItem (() => {
BuildAComputer ();
LetItRun ();
tcs.SetResult (42); // Terminate
});
return tcs.Task;
}
Awaiting Callbacks
Task<int> GetAnswerAsync ()
{
var tcs = new TaskCompletionSource<int> ();
GetAnswerCPS (
“input”,
(result, error) => {
if (error != null)
tcs.SetException (error);
else tcs.SetResult (result);
});
return tcs.Task;
}
Awaiting Callbacks
Task<int> GetAnswerAsync ()
{
var tcs = new TaskCompletionSource<int> ();
GetAnswerCPS (
“input”,
(result, error) => {
if (error != null)
tcs.SetException (error);
else tcs.SetResult (result);
});
return tcs.Task;
}
Awaiting Callbacks
Task<int> GetAnswerAsync ()
{
var tcs = new TaskCompletionSource<int> ();
GetAnswerCPS (
“input”,
(result, error) => {
if (error != null)
tcs.SetException (error);
else tcs.SetResult (result);
});
return tcs.Task;
}
Awaiting Callbacks
Task<int> GetAnswerAsync ()
{
var tcs = new TaskCompletionSource<int> ();
GetAnswerCPS (
“input”,
(result, error) => {
if (error != null)
tcs.SetException (error);
else tcs.SetResult (result);
});
return tcs.Task;
}
Awaiting Events
async Task EnterCode ()
{
// Must Tap buttons in the order 4, 2, 3, 3
await button4.Tapped ();
await button2.Tapped ();
await button3.Tapped ();
await button3.Tapped ();
// They get access
RevealSecretUI ();
}
Awaiting Events
static Task<EventArgs> Tapped (this UIButton btn)
{
var tcs = new TaskCompletionSource<int> ();
EventHandler handler;
handler = (s, e) => {
btn.TouchUpInside -= handler;
tcs.SetResult (e);
};
btn.TouchUpInside += handler;
return tcs.Task;
}
Awaiting Events
static Task<EventArgs> Tapped (this UIButton btn)
{
var tcs = new TaskCompletionSource<int> ();
EventHandler handler;
handler = (s, e) => {
btn.TouchUpInside -= handler;
tcs.SetResult (e);
};
btn.TouchUpInside += handler;
return tcs.Task;
}
Awaiting Events
static Task<EventArgs> Tapped (this UIButton btn)
{
var tcs = new TaskCompletionSource<int> ();
EventHandler handler;
handler = (s, e) => {
btn.TouchUpInside -= handler;
tcs.SetResult (e);
};
btn.TouchUpInside += handler;
return tcs.Task;
}
Awaiting Events
static Task<EventArgs> Tapped (this UIButton btn)
{
var tcs = new TaskCompletionSource<int> ();
EventHandler handler;
handler = (s, e) => {
btn.TouchUpInside -= handler;
tcs.SetResult (e);
};
btn.TouchUpInside += handler;
return tcs.Task;
}
Awaiting Generic Events
await button4.Tapped ();
await button4.Event (“TouchUpInside”);
Awaiting Generic Events
// Wait for the user to change the name of the
// model to “Frank”
var propEvent = await model.Event (
“PropertyChanged”,
x => x.Name == “Name” && model.Name == “Frank”);
Awaiting Generic Events
public static Task<EventArgs> Event (
this object eventSource,
string eventName,
Predicate<EventArgs> predicate = null)
{
var tcs = new TaskCompletionSource<EventArgs>();
var type = eventSource.GetType ();
var ev = type.GetEvent (eventName);
EventHandler handler;
handler = delegate (object sender, EventArgs e) {
if (predicate == null || predicate (e)) {
ev.RemoveEventHandler (eventSource, handler);
tcs.SetResult (e);
}
};
ev.AddEventHandler (eventSource, handler);
return tcs.Task;
}
Awaiting Generic Events
public static Task<EventArgs> Event (
this object eventSource,
string eventName,
Predicate<EventArgs> predicate = null)
{
var tcs = new TaskCompletionSource<EventArgs>();
var type = eventSource.GetType ();
var ev = type.GetEvent (eventName);
EventHandler handler;
handler = delegate (object sender, EventArgs e) {
if (predicate == null || predicate (e)) {
ev.RemoveEventHandler (eventSource, handler);
tcs.SetResult (e);
}
};
ev.AddEventHandler (eventSource, handler);
return tcs.Task;
}
Awaiting Generic Events
public static Task<EventArgs> Event (
this object eventSource,
string eventName,
Predicate<EventArgs> predicate = null)
{
var tcs = new TaskCompletionSource<EventArgs>();
var type = eventSource.GetType ();
var ev = type.GetEvent (eventName);
EventHandler handler;
handler = delegate (object sender, EventArgs e) {
if (predicate == null || predicate (e)) {
ev.RemoveEventHandler (eventSource, handler);
tcs.SetResult (e);
}
};
ev.AddEventHandler (eventSource, handler);
return tcs.Task;
}
Awaiting Generic Events
public static Task<EventArgs> Event (
this object eventSource,
string eventName,
Predicate<EventArgs> predicate = null)
{
var tcs = new TaskCompletionSource<EventArgs>();
var type = eventSource.GetType ();
var ev = type.GetEvent (eventName);
EventHandler handler;
handler = delegate (object sender, EventArgs e) {
if (predicate == null || predicate (e)) {
ev.RemoveEventHandler (eventSource, handler);
tcs.SetResult (e);
}
};
ev.AddEventHandler (eventSource, handler);
return tcs.Task;
}
Awaiting Generic Events
public static Task<EventArgs> Event (
this object eventSource,
string eventName,
Predicate<EventArgs> predicate = null)
{
var tcs = new TaskCompletionSource<EventArgs>();
var type = eventSource.GetType ();
var ev = type.GetEvent (eventName);
EventHandler handler;
handler = delegate (object sender, EventArgs e) {
if (predicate == null || predicate (e)) {
ev.RemoveEventHandler (eventSource, handler);
tcs.SetResult (e);
}
};
ev.AddEventHandler (eventSource, handler);
return tcs.Task;
}
button.TouchUpInside += async delegate {
var project = await ChooseProject ();
project.DoSomethingMindBlowing ();
}

AwaitingView Controllers
Task<Project> ChooseProject ()

{

var tcs = new TaskCompletionSource<Project> ();



var vc = new ChooseProjectViewController (projs);

vc.Completed += (s, e) => {

DismissViewController (true, null);

tcs.SetResult (vc.Project);

};



PresentViewController (vc, true, null);



return tcs.Task;

}

AwaitingView Controllers
Task<Project> ChooseProject ()

{

var tcs = new TaskCompletionSource<Project> ();



var vc = new ChooseProjectViewController (projs);

vc.Completed += (s, e) => {

DismissViewController (true, null);

tcs.SetResult (vc.Project);

};



PresentViewController (vc, true, null);



return tcs.Task;

}

AwaitingView Controllers
Task<Project> ChooseProject ()

{

var tcs = new TaskCompletionSource<Project> ();



var vc = new ChooseProjectViewController (projs);

vc.Completed += (s, e) => {

DismissViewController (true, null);

tcs.SetResult (vc.Project);

};



PresentViewController (vc, true, null);



return tcs.Task;

}

AwaitingView Controllers
Task<Project> ChooseProject ()

{

var tcs = new TaskCompletionSource<Project> ();



var vc = new ChooseProjectViewController (projs);

vc.Completed += (s, e) => {

DismissViewController (true, null);

tcs.SetResult (vc.Project);

};



PresentViewController (vc, true, null);



return tcs.Task;

}

AwaitingView Controllers
if (await Ask ("Archive", "Cancel") == 0) {
await Archive ();
}

Awaiting Dialogs
Task<int> Ask (params string[] answers)

{

var tcs = new TaskCompletionSource<int> ();



var sheet = new UIActionSheet ();

foreach (var a in answers)
sheet.AddButton (a);

sheet.CancelButtonIndex = answers.Length - 1;



sheet.Clicked += (s, e) => {

tcs.SetResult (e.ButtonIndex);

};



sheet.ShowFrom (View.Bounds, View, true);



return tcs.Task;

}

Awaiting Dialogs
Task<int> Ask (params string[] answers)

{

var tcs = new TaskCompletionSource<int> ();



var sheet = new UIActionSheet ();

foreach (var a in answers)
sheet.AddButton (a);

sheet.CancelButtonIndex = answers.Length - 1;



sheet.Clicked += (s, e) => {

tcs.SetResult (e.ButtonIndex);

};



sheet.ShowFrom (View.Bounds, View, true);



return tcs.Task;

}

Awaiting Dialogs
Task<int> Ask (params string[] answers)

{

var tcs = new TaskCompletionSource<int> ();



var sheet = new UIActionSheet ();

foreach (var a in answers)
sheet.AddButton (a);

sheet.CancelButtonIndex = answers.Length - 1;



sheet.Clicked += (s, e) => {

tcs.SetResult (e.ButtonIndex);

};



sheet.ShowFrom (View.Bounds, View, true);



return tcs.Task;

}

Awaiting Dialogs
Task<int> Ask (params string[] answers)

{

var tcs = new TaskCompletionSource<int> ();



var sheet = new UIActionSheet ();

foreach (var a in answers)
sheet.AddButton (a);

sheet.CancelButtonIndex = answers.Length - 1;



sheet.Clicked += (s, e) => {

tcs.SetResult (e.ButtonIndex);

};



sheet.ShowFrom (View.Bounds, View, true);



return tcs.Task;

}

Awaiting Dialogs
Task<int> Ask (params string[] answers)

{

var tcs = new TaskCompletionSource<int> ();



var sheet = new UIActionSheet ();

foreach (var a in answers)
sheet.AddButton (a);

sheet.CancelButtonIndex = answers.Length - 1;



sheet.Clicked += (s, e) => {

tcs.SetResult (e.ButtonIndex);

};



sheet.ShowFrom (View.Bounds, View, true);



return tcs.Task;

}

Awaiting Dialogs
And more...
Chaining Animations
Multi-gesture Recognition
Autonomous Services
...
Task
TaskCompletionSource
TaskScheduler
CancellationToken
TaskScheduler
Think of it as a Thread
TaskScheduler
Think of it as a Thread
it’s not though
TaskScheduler
Think of it as a Thread
it’s not though
but close enough
var tweets = await client.GetTweetsAsync ();
countLabel.Text = tweets.Count;
var tweets = await client.GetTweetsAsync ();
countLabel.Text = tweets.Count;
client.GetTweetsAsync ().ContinueWith (
t => {
if (t.IsFaulted)
throw new AggregateException (t.Exception);
countLabel.Text = tweets.Count;
},
TaskScheduler.FromCurrentSynchronizationContext ());
ConfigureAwait (false)
var tweets = await client.GetTweetsAsync ().
ConfigureAwait (false);
countLabel.Text = tweets.Count;
client.GetTweetsAsync ().ContinueWith (
t => {
if (t.IsFaulted)
throw new AggregateException (t.Exception);
countLabel.Text = tweets.Count;
});
var tweets = await client.GetTweetsAsync ().
ConfigureAwait (false);
countLabel.Text = tweets.Count;
Does not synchronize with the UI
Task
TaskCompletionSource
TaskScheduler
CancellationToken
CancellationToken
if (token.IsCancellationRequested) {
return;
}
CancellationToken
public Task LaunchTheRockets (
CancellationToken token);
CancellationTokenSource
var cts = new CancellationTokenSource ();
control.LaunchTheRockets (cts.Token);
CancellationTokenSource
var cts = new CancellationTokenSource ();
control.LaunchTheRockets (cts.Token);
// OMG, Cancel the rockets!
cts.Cancel ();
Why Async?
Why Await?
Tour of System.Threading.Tasks
with Real-world Uses of Await
Fak-world Uses of Await
Interlude
*
Map
Location
*
*
Thing
Monkey
GoldLiving Thing
Bat
*
Adventure
Player
IConsole
1
1
Adventure
Player
IConsole
1
interface IConsole
{
TextReader In { get; }
TextWriter Out { get; }
}

Adventure
public static void Main (string[] args)
{
var console = new ConsoleConsole ();
var map = Map.GenerateRandom ();
var player = new Player(
map.StartingLocation,
console);
player.Play ().Wait ();
}

Adventurepublic async Task Play ()
{
while (true) {
// Print the status
await console.Out.WriteLineAsync (Location.Description);
await console.Out.WriteLineAsync (Status);
// Read the command from the user
var command = await console.In.ReadLineAsync ();
if (!string.IsNullOrWhiteSpace (command)) {
// Execute it
var result = Execute (command);
// Print the result
await console.Out.WriteLineAsync (result);
}
}
}

Why Async?
Why Await?
Tour of System.Threading.Tasks
with Real-world Uses of Await
Fak-world Uses of Await
Recognizing
Asynchronous Events
async Task EnterCode ()
{
// Must Tap buttons in the order 4, 2, 3, 3
await button4.Tapped ();
await button2.Tapped ();
await button3.Tapped ();
await button3.Tapped ();
// They get access
RevealSecretUI ();
}
Recognizing
Asynchronous Events
Recognizing
Asynchronous Events
Recognizing
Human Time Events
Async Tutorial
async Task ShowTheUserHowToSearch ()
{
await Tutorial.EnterText
(searchField, minLength: 3);
await Tutorial.Tap
(searchButton);
await Tutorial.Congratulate
("Now you know how to search.");
}

http://praeclarum.org/post/45277337108
Recognizing
Asynchronous Events
Recognizing
Human Time Events
Web Requests are
Human Time
Turn the Web Server
Inside Out
Instead of waiting for random
requests, specify the requests
you want in the order you
want them.
public class StepByStepServer : WebServer
{
protected override async Task RunSession (WebSession session)
{
await session.Get ("/");
await session.Out.WriteLineAsync (
"<html><h1>Home</h1><a href='step1'>Next</a></html>");
await session.Get ("/hello");
await session.Out.WriteLineAsync (
"<html><h1>Hello</h1><a href='done'>Finish</a></html>");
await session.Get ("/done");
await session.Out.WriteLineAsync (
"<html><h1>Yay!</h1><a href='/'>Start Over</a></html>");
}
}




public class CounterServer : WebServer
{
protected override async Task RunSession (WebSession session)
{
for (var i = 3; i >= 1; i--) {
await session.Get ();
await session.Out.WriteAsync (i.ToString ());
}
while (true) {
await session.Get ();
await session.Out.WriteAsync ("Go MonkeySpace!");
}
}
}

Seattle? WTF?
class WebConsole : IConsole
Adventure on the Web
using the same code as
the Console
public class GameServer : WebServer
{
Map map;
public GameServer (Map map)
{
this.map = map;
}
protected override async Task RunSession (WebSession session)
{
var console = new WebConsole (session);
var player = new Player (map.StartingLocation, console);
await player.Play ();
}
}

public class GameServer : WebServer
{
Map map;
public GameServer (Map map)
{
this.map = map;
}
protected override async Task RunSession (WebSession session)
{
var console = new WebConsole (session);
var player = new Player (map.StartingLocation, console);
await player.Play ();
}
}

public class GameServer : WebServer
{
Map map;
public GameServer (Map map)
{
this.map = map;
}
protected override async Task RunSession (WebSession session)
{
var console = new WebConsole (session);
var player = new Player (map.StartingLocation, console);
await player.Play ();
}
}

Multiplayer
Thank you!
Resources
Channel 9 - http://channel9.msdn.com
Xamarin EvolveVideos - http://xamarin.com/evolve/2013
Ask Jon Skeet
Asynchronous Application Patterns in C# - MonkeySpace

More Related Content

Similar to Asynchronous Application Patterns in C# - MonkeySpace

Category theory, Monads, and Duality in the world of (BIG) Data
Category theory, Monads, and Duality in the world of (BIG) DataCategory theory, Monads, and Duality in the world of (BIG) Data
Category theory, Monads, and Duality in the world of (BIG) Data
greenwop
 
@Anywhere
@Anywhere@Anywhere
@Anywhere
toddkloots
 
Akka
AkkaAkka
망고100 보드로 놀아보자 19
망고100 보드로 놀아보자 19망고100 보드로 놀아보자 19
망고100 보드로 놀아보자 19
종인 전
 
Building @Anywhere (for TXJS)
Building @Anywhere (for TXJS)Building @Anywhere (for TXJS)
Building @Anywhere (for TXJS)
danwrong
 
CSharp for Unity Day2
CSharp for Unity Day2CSharp for Unity Day2
CSharp for Unity Day2
Duong Thanh
 
Orsiso
OrsisoOrsiso
Orsiso
e27
 
Shipping Pseudocode to Production VarnaLab
Shipping Pseudocode to Production VarnaLabShipping Pseudocode to Production VarnaLab
Shipping Pseudocode to Production VarnaLab
Dobromir Nikolov
 
Non Blocking I/O for Everyone with RxJava
Non Blocking I/O for Everyone with RxJavaNon Blocking I/O for Everyone with RxJava
Non Blocking I/O for Everyone with RxJava
Frank Lyaruu
 
The Death of a Mouse
The Death of a MouseThe Death of a Mouse
The Death of a Mouse
Geert Bevin
 
C#을 이용한 task 병렬화와 비동기 패턴
C#을 이용한 task 병렬화와 비동기 패턴C#을 이용한 task 병렬화와 비동기 패턴
C#을 이용한 task 병렬화와 비동기 패턴
명신 김
 
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Domenic Denicola
 
A Playful Introduction to Rx
A Playful Introduction to RxA Playful Introduction to Rx
A Playful Introduction to Rx
Andrey Cheptsov
 
Async await
Async awaitAsync await
Async await
Jeff Hart
 
Android Threading
Android ThreadingAndroid Threading
Android Threading
Jussi Pohjolainen
 
Resiliency & Security_Ballerina Day CMB 2018
Resiliency & Security_Ballerina Day CMB 2018  Resiliency & Security_Ballerina Day CMB 2018
Resiliency & Security_Ballerina Day CMB 2018
Ballerina
 
MultiClient chatting berbasis gambar
MultiClient chatting berbasis gambarMultiClient chatting berbasis gambar
MultiClient chatting berbasis gambar
yoyomay93
 
Play image
Play imagePlay image
Play image
Fardian Syah
 
Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#
Juan Pablo
 
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
DroidConTLV
 

Similar to Asynchronous Application Patterns in C# - MonkeySpace (20)

Category theory, Monads, and Duality in the world of (BIG) Data
Category theory, Monads, and Duality in the world of (BIG) DataCategory theory, Monads, and Duality in the world of (BIG) Data
Category theory, Monads, and Duality in the world of (BIG) Data
 
@Anywhere
@Anywhere@Anywhere
@Anywhere
 
Akka
AkkaAkka
Akka
 
망고100 보드로 놀아보자 19
망고100 보드로 놀아보자 19망고100 보드로 놀아보자 19
망고100 보드로 놀아보자 19
 
Building @Anywhere (for TXJS)
Building @Anywhere (for TXJS)Building @Anywhere (for TXJS)
Building @Anywhere (for TXJS)
 
CSharp for Unity Day2
CSharp for Unity Day2CSharp for Unity Day2
CSharp for Unity Day2
 
Orsiso
OrsisoOrsiso
Orsiso
 
Shipping Pseudocode to Production VarnaLab
Shipping Pseudocode to Production VarnaLabShipping Pseudocode to Production VarnaLab
Shipping Pseudocode to Production VarnaLab
 
Non Blocking I/O for Everyone with RxJava
Non Blocking I/O for Everyone with RxJavaNon Blocking I/O for Everyone with RxJava
Non Blocking I/O for Everyone with RxJava
 
The Death of a Mouse
The Death of a MouseThe Death of a Mouse
The Death of a Mouse
 
C#을 이용한 task 병렬화와 비동기 패턴
C#을 이용한 task 병렬화와 비동기 패턴C#을 이용한 task 병렬화와 비동기 패턴
C#을 이용한 task 병렬화와 비동기 패턴
 
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
 
A Playful Introduction to Rx
A Playful Introduction to RxA Playful Introduction to Rx
A Playful Introduction to Rx
 
Async await
Async awaitAsync await
Async await
 
Android Threading
Android ThreadingAndroid Threading
Android Threading
 
Resiliency & Security_Ballerina Day CMB 2018
Resiliency & Security_Ballerina Day CMB 2018  Resiliency & Security_Ballerina Day CMB 2018
Resiliency & Security_Ballerina Day CMB 2018
 
MultiClient chatting berbasis gambar
MultiClient chatting berbasis gambarMultiClient chatting berbasis gambar
MultiClient chatting berbasis gambar
 
Play image
Play imagePlay image
Play image
 
Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#
 
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
 

More from Frank Krueger

Open Source CLRs - Seattle Mobile .NET
Open Source CLRs - Seattle Mobile .NETOpen Source CLRs - Seattle Mobile .NET
Open Source CLRs - Seattle Mobile .NET
Frank Krueger
 
Programming Augmented Reality - Xamarin Evolve
Programming Augmented Reality - Xamarin EvolveProgramming Augmented Reality - Xamarin Evolve
Programming Augmented Reality - Xamarin Evolve
Frank Krueger
 
3 Mobile App Dev Problems - Monospace
3 Mobile App Dev Problems - Monospace3 Mobile App Dev Problems - Monospace
3 Mobile App Dev Problems - Monospace
Frank Krueger
 
Algorithms - Future Decoded 2016
Algorithms - Future Decoded 2016Algorithms - Future Decoded 2016
Algorithms - Future Decoded 2016
Frank Krueger
 
How I Made Zoom In and Enhance - Seattle Mobile .NET
How I Made Zoom In and Enhance - Seattle Mobile .NETHow I Made Zoom In and Enhance - Seattle Mobile .NET
How I Made Zoom In and Enhance - Seattle Mobile .NET
Frank Krueger
 
Overview of iOS 11 - Seattle Mobile .NET
Overview of iOS 11 - Seattle Mobile .NETOverview of iOS 11 - Seattle Mobile .NET
Overview of iOS 11 - Seattle Mobile .NET
Frank Krueger
 
Functional GUIs with F#
Functional GUIs with F#Functional GUIs with F#
Functional GUIs with F#
Frank Krueger
 
Mocast Postmortem
Mocast PostmortemMocast Postmortem
Mocast Postmortem
Frank Krueger
 
Programming iOS in C#
Programming iOS in C#Programming iOS in C#
Programming iOS in C#
Frank Krueger
 

More from Frank Krueger (9)

Open Source CLRs - Seattle Mobile .NET
Open Source CLRs - Seattle Mobile .NETOpen Source CLRs - Seattle Mobile .NET
Open Source CLRs - Seattle Mobile .NET
 
Programming Augmented Reality - Xamarin Evolve
Programming Augmented Reality - Xamarin EvolveProgramming Augmented Reality - Xamarin Evolve
Programming Augmented Reality - Xamarin Evolve
 
3 Mobile App Dev Problems - Monospace
3 Mobile App Dev Problems - Monospace3 Mobile App Dev Problems - Monospace
3 Mobile App Dev Problems - Monospace
 
Algorithms - Future Decoded 2016
Algorithms - Future Decoded 2016Algorithms - Future Decoded 2016
Algorithms - Future Decoded 2016
 
How I Made Zoom In and Enhance - Seattle Mobile .NET
How I Made Zoom In and Enhance - Seattle Mobile .NETHow I Made Zoom In and Enhance - Seattle Mobile .NET
How I Made Zoom In and Enhance - Seattle Mobile .NET
 
Overview of iOS 11 - Seattle Mobile .NET
Overview of iOS 11 - Seattle Mobile .NETOverview of iOS 11 - Seattle Mobile .NET
Overview of iOS 11 - Seattle Mobile .NET
 
Functional GUIs with F#
Functional GUIs with F#Functional GUIs with F#
Functional GUIs with F#
 
Mocast Postmortem
Mocast PostmortemMocast Postmortem
Mocast Postmortem
 
Programming iOS in C#
Programming iOS in C#Programming iOS in C#
Programming iOS in C#
 

Recently uploaded

Webinar On-Demand: Using Flutter for Embedded
Webinar On-Demand: Using Flutter for EmbeddedWebinar On-Demand: Using Flutter for Embedded
Webinar On-Demand: Using Flutter for Embedded
ICS
 
Oracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptxOracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptx
Remote DBA Services
 
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise EditionWhy Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
Envertis Software Solutions
 
Microservice Teams - How the cloud changes the way we work
Microservice Teams - How the cloud changes the way we workMicroservice Teams - How the cloud changes the way we work
Microservice Teams - How the cloud changes the way we work
Sven Peters
 
SWEBOK and Education at FUSE Okinawa 2024
SWEBOK and Education at FUSE Okinawa 2024SWEBOK and Education at FUSE Okinawa 2024
SWEBOK and Education at FUSE Okinawa 2024
Hironori Washizaki
 
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOMLORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
lorraineandreiamcidl
 
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of CodeA Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
Aftab Hussain
 
What is Augmented Reality Image Tracking
What is Augmented Reality Image TrackingWhat is Augmented Reality Image Tracking
What is Augmented Reality Image Tracking
pavan998932
 
GraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph TechnologyGraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph Technology
Neo4j
 
Unveiling the Advantages of Agile Software Development.pdf
Unveiling the Advantages of Agile Software Development.pdfUnveiling the Advantages of Agile Software Development.pdf
Unveiling the Advantages of Agile Software Development.pdf
brainerhub1
 
Oracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptxOracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptx
Remote DBA Services
 
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Łukasz Chruściel
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
Safe Software
 
Graspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code AnalysisGraspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code Analysis
Aftab Hussain
 
Empowering Growth with Best Software Development Company in Noida - Deuglo
Empowering Growth with Best Software  Development Company in Noida - DeugloEmpowering Growth with Best Software  Development Company in Noida - Deuglo
Empowering Growth with Best Software Development Company in Noida - Deuglo
Deuglo Infosystem Pvt Ltd
 
openEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain SecurityopenEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain Security
Shane Coughlan
 
socradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdfsocradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdf
SOCRadar
 
Fundamentals of Programming and Language Processors
Fundamentals of Programming and Language ProcessorsFundamentals of Programming and Language Processors
Fundamentals of Programming and Language Processors
Rakesh Kumar R
 
How to write a program in any programming language
How to write a program in any programming languageHow to write a program in any programming language
How to write a program in any programming language
Rakesh Kumar R
 
Vitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdfVitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke
 

Recently uploaded (20)

Webinar On-Demand: Using Flutter for Embedded
Webinar On-Demand: Using Flutter for EmbeddedWebinar On-Demand: Using Flutter for Embedded
Webinar On-Demand: Using Flutter for Embedded
 
Oracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptxOracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptx
 
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise EditionWhy Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
 
Microservice Teams - How the cloud changes the way we work
Microservice Teams - How the cloud changes the way we workMicroservice Teams - How the cloud changes the way we work
Microservice Teams - How the cloud changes the way we work
 
SWEBOK and Education at FUSE Okinawa 2024
SWEBOK and Education at FUSE Okinawa 2024SWEBOK and Education at FUSE Okinawa 2024
SWEBOK and Education at FUSE Okinawa 2024
 
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOMLORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
LORRAINE ANDREI_LEQUIGAN_HOW TO USE ZOOM
 
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of CodeA Study of Variable-Role-based Feature Enrichment in Neural Models of Code
A Study of Variable-Role-based Feature Enrichment in Neural Models of Code
 
What is Augmented Reality Image Tracking
What is Augmented Reality Image TrackingWhat is Augmented Reality Image Tracking
What is Augmented Reality Image Tracking
 
GraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph TechnologyGraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph Technology
 
Unveiling the Advantages of Agile Software Development.pdf
Unveiling the Advantages of Agile Software Development.pdfUnveiling the Advantages of Agile Software Development.pdf
Unveiling the Advantages of Agile Software Development.pdf
 
Oracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptxOracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptx
 
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
 
Graspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code AnalysisGraspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code Analysis
 
Empowering Growth with Best Software Development Company in Noida - Deuglo
Empowering Growth with Best Software  Development Company in Noida - DeugloEmpowering Growth with Best Software  Development Company in Noida - Deuglo
Empowering Growth with Best Software Development Company in Noida - Deuglo
 
openEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain SecurityopenEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain Security
 
socradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdfsocradar-q1-2024-aviation-industry-report.pdf
socradar-q1-2024-aviation-industry-report.pdf
 
Fundamentals of Programming and Language Processors
Fundamentals of Programming and Language ProcessorsFundamentals of Programming and Language Processors
Fundamentals of Programming and Language Processors
 
How to write a program in any programming language
How to write a program in any programming languageHow to write a program in any programming language
How to write a program in any programming language
 
Vitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdfVitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdf
 

Asynchronous Application Patterns in C# - MonkeySpace

  • 1. Asynchronous Application Patterns in C# Frank A. Krueger @praeclarum
  • 2. Async How C# Makes Every Other Language Look Stupid Frank A. Krueger @praeclarum
  • 3. Why Async? Why Await? Tour of System.Threading.Tasks with Real-world Uses of Await Fak-world Uses of Await
  • 4. Why Async? Why Await? Tour of System.Threading.Tasks with Real-world Uses of Await Fak-world Uses of Await
  • 5. Apps are Async • Interacting with the user • Performing computations • Downloading resources from the web • Uploading actions and messages to services • Reading and writing local storage • Watching for motion changes, camera or microphone events, network connectivity, etc.
  • 8. You can’t do anything!
  • 10. And So Async... • .NET Events • .NET 1.0 Async (IAsyncResult)
  • 11. And So Async... • .NET Events • .NET 1.0 Async (IAsyncResult) • Closures! Continuation Passing Style FTW!
  • 12. And So Async... • .NET Events • .NET 1.0 Async (IAsyncResult) • Closures! Continuation Passing Style FTW! • IObservable<T>
  • 13. And So Async... • .NET Events • .NET 1.0 Async (IAsyncResult) • Closures! Continuation Passing Style FTW! • IObservable<T> ARVIS
  • 14. And So Async... • .NET Events • .NET 1.0 Async (IAsyncResult) • Closures! Continuation Passing Style FTW! • IObservable<T> Asynchronous Retrieval of Values from Infinite Streams
  • 15. And So Async... • .NET Events • .NET 1.0 Async (IAsyncResult) • Closures! Continuation Passing Style FTW! • IObservable<T> • iOS Delegates
  • 16. And So Async... • .NET Events • .NET 1.0 Async (IAsyncResult) • Closures! Continuation Passing Style FTW! • IObservable<T> • iOS Delegates • iOS Callbacks (Obj-C bocks)
  • 17. And So Async... • .NET Events • .NET 1.0 Async (IAsyncResult) • Closures! Continuation Passing Style FTW! • IObservable<T> • iOS Delegates • iOS Callbacks (Obj-C bocks) • Android Listeners, Event Interfaces
  • 18. Why Async? Why Await? Tour of System.Threading.Tasks with Real-world Uses of Await Fak-world Uses of Await
  • 19. hugMeanPeopleButton.TouchUpInside += delegate { // Network IO var tweets = twitterClient.GetMentions (); // Computation var q = from t tweets where t.IsMean select t; // Lots of Network IO foreach (var enemy in q) { twitterClient.Reply (enemy, “Here’s a hug”); } // UI statusLabel.Text = string.Join (“, “, q.Select (x => x.Name)) + “ have been hugged”; }; ©®™ 2013 Krueger Systems, Inc. All Rights Reserved.
  • 20. hugMeanPeopleButton.TouchUpInside += delegate { // Network IO var tweets = twitterClient.GetMentions (); // Computation var q = from t tweets where t.IsMean select t; // Lots of Network IO foreach (var enemy in q) { twitterClient.Reply (enemy, “Here’s a hug”); } // UI statusLabel.Text = string.Join (“, “, q.Select (x => x.Name)) + “ have been hugged”; }; Slow Slow x N Slow?
  • 21. hugMeanPeopleButton.TouchUpInside += delegate { // Network IO twitterClient.GetMentions ( (tweets, tweetsError) => { if (tweetsError != null) Umm (tweetsError); // Computation var q = from t in tweets where t.IsMean select t; // This is a loop, believe it or not tweetsToHug = q.ToList (); nextTweetToHug = 0; HugTweet (); }); } List<Tweet> tweetsToHug = null; int nextTweetToHug = 0; void HugTweet () { if (tweetsToHug == null) return; // Lots of Network IO if (nextTweetToHug < tweetsToHug.Count) { var t = tweetsToHug [nextTweetToHug++]; twitterClient.Reply ( t, “Here’s a hug”, replyError => { if (replyError != null) Umm (replyError); HugTweet (); }); return; } // UI statusLabel.Text = string.Join (“, “,tweetsToHug.Select(x=>x.Name)) + “ have been hugged”; tweetsToHug = null; } Continuation Passing Style (CPS)
  • 22. hugMeanPeopleButton.TouchUpInside += delegate { // Network IO twitterClient.GetMentions ( (tweets, tweetsError) => { if (tweetsError != null) Umm (tweetsError); // Computation var q = from t in tweets where t.IsMean select t; // This is a loop, believe it or not tweetsToHug = q.ToList (); nextTweetToHug = 0; HugTweet (); }); } List<Tweet> tweetsToHug = null; int nextTweetToHug = 0; void HugTweet () { if (tweetsToHug == null) return; // Lots of Network IO if (nextTweetToHug < tweetsToHug.Count) { var t = tweetsToHug [nextTweetToHug++]; twitterClient.Reply ( t, “Here’s a hug”, replyError => { if (replyError != null) Umm (replyError); HugTweet (); }); return; } // UI statusLabel.Text = string.Join (“, “,tweetsToHug.Select(x=>x.Name)) + “ have been hugged”; tweetsToHug = null; } 2 Functions?
  • 23. hugMeanPeopleButton.TouchUpInside += delegate { // Network IO twitterClient.GetMentions ( (tweets, tweetsError) => { if (tweetsError != null) Umm (tweetsError); // Computation var q = from t in tweets where t.IsMean select t; // This is a loop, believe it or not tweetsToHug = q.ToList (); nextTweetToHug = 0; HugTweet (); }); } List<Tweet> tweetsToHug = null; int nextTweetToHug = 0; void HugTweet () { if (tweetsToHug == null) return; // Lots of Network IO if (nextTweetToHug < tweetsToHug.Count) { var t = tweetsToHug [nextTweetToHug++]; twitterClient.Reply ( t, “Here’s a hug”, replyError => { if (replyError != null) Umm (replyError); HugTweet (); }); return; } // UI statusLabel.Text = string.Join (“, “,tweetsToHug.Select(x=>x.Name)) + “ have been hugged”; tweetsToHug = null; } StateVariables?
  • 24. hugMeanPeopleButton.TouchUpInside += delegate { // Network IO twitterClient.GetMentions ( (tweets, tweetsError) => { if (tweetsError != null) Umm (tweetsError); // Computation var q = from t in tweets where t.IsMean select t; // This is a loop, believe it or not tweetsToHug = q.ToList (); nextTweetToHug = 0; HugTweet (); }); } List<Tweet> tweetsToHug = null; int nextTweetToHug = 0; void HugTweet () { if (tweetsToHug == null) return; // Lots of Network IO if (nextTweetToHug < tweetsToHug.Count) { var t = tweetsToHug [nextTweetToHug++]; twitterClient.Reply ( t, “Here’s a hug”, replyError => { if (replyError != null) Umm (replyError); HugTweet (); }); return; } // UI statusLabel.Text = string.Join (“, “,tweetsToHug.Select(x=>x.Name)) + “ have been hugged”; tweetsToHug = null; } Subtle but Critical Assignments?
  • 25. hugMeanPeopleButton.TouchUpInside += delegate { // Network IO twitterClient.GetMentions ( (tweets, tweetsError) => { if (tweetsError != null) Umm (tweetsError); // Computation var q = from t in tweets where t.IsMean select t; // This is a loop, believe it or not tweetsToHug = q.ToList (); nextTweetToHug = 0; HugTweet (); }); } List<Tweet> tweetsToHug = null; int nextTweetToHug = 0; void HugTweet () { if (tweetsToHug == null) return; // Lots of Network IO if (nextTweetToHug < tweetsToHug.Count) { var t = tweetsToHug [nextTweetToHug++]; twitterClient.Reply ( t, “Here’s a hug”, replyError => { if (replyError != null) Umm (replyError); HugTweet (); }); return; } // UI statusLabel.Text = string.Join (“, “,tweetsToHug.Select(x=>x.Name)) + “ have been hugged”; tweetsToHug = null; } Recursion?
  • 26. hugMeanPeopleButton.TouchUpInside += delegate { // Network IO twitterClient.GetMentions ( (tweets, tweetsError) => { if (tweetsError != null) Umm (tweetsError); // Computation var q = from t in tweets where t.IsMean select t; // This is a loop, believe it or not tweetsToHug = q.ToList (); nextTweetToHug = 0; HugTweet (); }); } List<Tweet> tweetsToHug = null; int nextTweetToHug = 0; void HugTweet () { if (tweetsToHug == null) return; // Lots of Network IO if (nextTweetToHug < tweetsToHug.Count) { var t = tweetsToHug [nextTweetToHug++]; twitterClient.Reply ( t, “Here’s a hug”, replyError => { if (replyError != null) Umm (replyError); HugTweet (); }); return; } // UI statusLabel.Text = string.Join (“, “,tweetsToHug.Select(x=>x.Name)) + “ have been hugged”; tweetsToHug = null; } Tail End of Process in a Strange Function?
  • 27. hugMeanPeopleButton.TouchUpInside += delegate { // Network IO twitterClient.GetMentions ( (tweets, tweetsError) => { if (tweetsError != null) Umm (tweetsError); // Computation var q = from t in tweets where t.IsMean select t; // This is a loop, believe it or not tweetsToHug = q.ToList (); nextTweetToHug = 0; HugTweet (); }); } List<Tweet> tweetsToHug = null; int nextTweetToHug = 0; void HugTweet () { if (tweetsToHug == null) return; // Lots of Network IO if (nextTweetToHug < tweetsToHug.Count) { var t = tweetsToHug [nextTweetToHug++]; twitterClient.Reply ( t, “Here’s a hug”, replyError => { if (replyError != null) Umm (replyError); HugTweet (); }); return; } // UI statusLabel.Text = string.Join (“, “,tweetsToHug.Select(x=>x.Name)) + “ have been hugged”; tweetsToHug = null; } Umm...
  • 28. Our Languages Were Not Designed for Asynchronous Procedures
  • 32. hugMeanPeopleButton.TouchUpInside += delegate { // Network IO var tweets = twitterClient.GetMentions (); // Computation var q = from t tweets where t.IsMean select t; // Lots of Network IO foreach (var enemy in q) { twitterClient.Reply (t, “Here’s a hug”); } // UI statusLabel.Text = string.Join (“, “, q.Select (x => x.Name)) + “ have been hugged”; };
  • 33. hugMeanPeopleButton.TouchUpInside += async delegate { // Network IO var tweets = await twitterClient.GetMentionsAsync (); // Computation var q = from t tweets where t.IsMean select t; // Lots of Network IO foreach (var enemy in q) { await twitterClient.ReplyAsync (t, “Here’s a hug”); } // UI statusLabel.Text = string.Join (“, “, q.Select (x => x.Name)) + “ have been hugged”; };
  • 34. hugMeanPeopleButton.TouchUpInside += async delegate { // Network IO var tweets = await twitterClient.GetMentionsAsync (); // Computation var q = from t tweets where t.IsMean select t; // Lots of Network IO foreach (var enemy in q) { await twitterClient.ReplyAsync (t, “Here’s a hug”); } // UI statusLabel.Text = string.Join (“, “, q.Select (x => x.Name)) + “ have been hugged”; };
  • 35. hugMeanPeopleButton.TouchUpInside += async delegate { // Network IO var tweets = await twitterClient.GetMentionsAsync (); // Computation, in the Background, dood var q = await Task.Run (() => from t tweets where t.IsMean select t); // Lots of Network IO foreach (var enemy in q) { await twitterClient.ReplyAsync (t, “Here’s a hug”); } // UI statusLabel.Text = string.Join (“, “, q.Select (x => x.Name)) + “ have been hugged”; };
  • 37. Why Async? Why Await? Tour of System.Threading.Tasks with Real-world Uses of Await Fak-world Uses of Await
  • 39. System.Threading.Task Parallel Process await task; // Async task.Wait (); // Synchronous
  • 40. System.Threading.Task Fallible Parallel Process try { await task; // Async task.Wait (); // Synchronous } catch (Exception) { }
  • 41. System.Threading.Task<T> Parallel Process That Returns aValue var value = await task; // Async task.Wait (); // Synchronous var value = task.Result;
  • 42. Where do Tasks come from?
  • 43. var tweets = await client.GetTweetsAsync (); await client.PostAsync (“Hello, World!”); Call an Async Method
  • 44. var tweets = await client.GetTweetsAsync (); await client.PostAsync (“Hello, World!”); Call an Async Method Network? CPU? UI?
  • 45. var value = await Task.Run (() => { return 42; }); await Task.Run (() => { LaunchMissiles (); }); Start a Background Task Using a Function
  • 47. mesh = await Task.Run (() => sphere.Tesselate (opts));
  • 48. async Task<int> GetPopularityAsync () { var followers = await twitter.GetFollowersAsync (); return followers.Sum ( x => x.FollowerCount); } Methods That Use await Return Tasks
  • 49. var value = await Task.Factory.FromAsync ( foo.BeginDoingSomething, foo.EndDoingSomething, null); From .NET 1.0 Async
  • 50. await Task.Factory.ContinueWhenAll ( downloadTasks, ts => {}); Combinators await Task.Factory.ContinueWhenAny ( actionStartGestures, t => {});
  • 51. await Task.Factory.ContinueWhenAll ( downloadTasks, ts => {}); Combinators await Task.Factory.ContinueWhenAny ( actionStartGestures, t => {}); Take Multiple Tasks and turn them into One Task
  • 52. async Task UpdatePodcasts () { ShowUpdatingUI (); foreach (var feed in feeds) { await feed.Update (); } ShowUpdatingCompletedUI (); } Concurrency?
  • 53. async Task UpdatePodcasts () { ShowUpdatingUI (); foreach (var feed in feeds) { await feed.Update (); } ShowUpdatingCompletedUI (); } Concurrency? Sequential
  • 54. async Task UpdatePodcasts () { ShowUpdatingUI (); Task.Factory.ContinueWhenAll ( feeds.Select (x => x.Update ()), null); ShowUpdatingCompletedUI (); } Concurrency! Parallel
  • 57. TaskCompletionSource<T> Great way to interact with ancient, old, fuddy duddy, outdated async models
  • 59. Task<int> GetAnswerAsync () { var tcs = new TaskCompletionSource<int> (); ThreadPool.QueueUserWorkItem (() => { BuildAComputer (); LetItRun (); tcs.SetResult (42); // Terminate }); return tcs.Task; }
  • 60. Task<int> GetAnswerAsync () { var tcs = new TaskCompletionSource<int> (); ThreadPool.QueueUserWorkItem (() => { BuildAComputer (); LetItRun (); tcs.SetResult (42); // Terminate }); return tcs.Task; }
  • 61. Task<int> GetAnswerAsync () { var tcs = new TaskCompletionSource<int> (); ThreadPool.QueueUserWorkItem (() => { BuildAComputer (); LetItRun (); tcs.SetResult (42); // Terminate }); return tcs.Task; }
  • 62. Task<int> GetAnswerAsync () { var tcs = new TaskCompletionSource<int> (); ThreadPool.QueueUserWorkItem (() => { BuildAComputer (); LetItRun (); tcs.SetResult (42); // Terminate }); return tcs.Task; }
  • 63. Task<int> GetAnswerAsync () { var tcs = new TaskCompletionSource<int> (); ThreadPool.QueueUserWorkItem (() => { BuildAComputer (); LetItRun (); tcs.SetResult (42); // Terminate }); return tcs.Task; }
  • 64. Awaiting Callbacks Task<int> GetAnswerAsync () { var tcs = new TaskCompletionSource<int> (); GetAnswerCPS ( “input”, (result, error) => { if (error != null) tcs.SetException (error); else tcs.SetResult (result); }); return tcs.Task; }
  • 65. Awaiting Callbacks Task<int> GetAnswerAsync () { var tcs = new TaskCompletionSource<int> (); GetAnswerCPS ( “input”, (result, error) => { if (error != null) tcs.SetException (error); else tcs.SetResult (result); }); return tcs.Task; }
  • 66. Awaiting Callbacks Task<int> GetAnswerAsync () { var tcs = new TaskCompletionSource<int> (); GetAnswerCPS ( “input”, (result, error) => { if (error != null) tcs.SetException (error); else tcs.SetResult (result); }); return tcs.Task; }
  • 67. Awaiting Callbacks Task<int> GetAnswerAsync () { var tcs = new TaskCompletionSource<int> (); GetAnswerCPS ( “input”, (result, error) => { if (error != null) tcs.SetException (error); else tcs.SetResult (result); }); return tcs.Task; }
  • 68. Awaiting Events async Task EnterCode () { // Must Tap buttons in the order 4, 2, 3, 3 await button4.Tapped (); await button2.Tapped (); await button3.Tapped (); await button3.Tapped (); // They get access RevealSecretUI (); }
  • 69. Awaiting Events static Task<EventArgs> Tapped (this UIButton btn) { var tcs = new TaskCompletionSource<int> (); EventHandler handler; handler = (s, e) => { btn.TouchUpInside -= handler; tcs.SetResult (e); }; btn.TouchUpInside += handler; return tcs.Task; }
  • 70. Awaiting Events static Task<EventArgs> Tapped (this UIButton btn) { var tcs = new TaskCompletionSource<int> (); EventHandler handler; handler = (s, e) => { btn.TouchUpInside -= handler; tcs.SetResult (e); }; btn.TouchUpInside += handler; return tcs.Task; }
  • 71. Awaiting Events static Task<EventArgs> Tapped (this UIButton btn) { var tcs = new TaskCompletionSource<int> (); EventHandler handler; handler = (s, e) => { btn.TouchUpInside -= handler; tcs.SetResult (e); }; btn.TouchUpInside += handler; return tcs.Task; }
  • 72. Awaiting Events static Task<EventArgs> Tapped (this UIButton btn) { var tcs = new TaskCompletionSource<int> (); EventHandler handler; handler = (s, e) => { btn.TouchUpInside -= handler; tcs.SetResult (e); }; btn.TouchUpInside += handler; return tcs.Task; }
  • 73. Awaiting Generic Events await button4.Tapped (); await button4.Event (“TouchUpInside”);
  • 74. Awaiting Generic Events // Wait for the user to change the name of the // model to “Frank” var propEvent = await model.Event ( “PropertyChanged”, x => x.Name == “Name” && model.Name == “Frank”);
  • 75. Awaiting Generic Events public static Task<EventArgs> Event ( this object eventSource, string eventName, Predicate<EventArgs> predicate = null) { var tcs = new TaskCompletionSource<EventArgs>(); var type = eventSource.GetType (); var ev = type.GetEvent (eventName); EventHandler handler; handler = delegate (object sender, EventArgs e) { if (predicate == null || predicate (e)) { ev.RemoveEventHandler (eventSource, handler); tcs.SetResult (e); } }; ev.AddEventHandler (eventSource, handler); return tcs.Task; }
  • 76. Awaiting Generic Events public static Task<EventArgs> Event ( this object eventSource, string eventName, Predicate<EventArgs> predicate = null) { var tcs = new TaskCompletionSource<EventArgs>(); var type = eventSource.GetType (); var ev = type.GetEvent (eventName); EventHandler handler; handler = delegate (object sender, EventArgs e) { if (predicate == null || predicate (e)) { ev.RemoveEventHandler (eventSource, handler); tcs.SetResult (e); } }; ev.AddEventHandler (eventSource, handler); return tcs.Task; }
  • 77. Awaiting Generic Events public static Task<EventArgs> Event ( this object eventSource, string eventName, Predicate<EventArgs> predicate = null) { var tcs = new TaskCompletionSource<EventArgs>(); var type = eventSource.GetType (); var ev = type.GetEvent (eventName); EventHandler handler; handler = delegate (object sender, EventArgs e) { if (predicate == null || predicate (e)) { ev.RemoveEventHandler (eventSource, handler); tcs.SetResult (e); } }; ev.AddEventHandler (eventSource, handler); return tcs.Task; }
  • 78. Awaiting Generic Events public static Task<EventArgs> Event ( this object eventSource, string eventName, Predicate<EventArgs> predicate = null) { var tcs = new TaskCompletionSource<EventArgs>(); var type = eventSource.GetType (); var ev = type.GetEvent (eventName); EventHandler handler; handler = delegate (object sender, EventArgs e) { if (predicate == null || predicate (e)) { ev.RemoveEventHandler (eventSource, handler); tcs.SetResult (e); } }; ev.AddEventHandler (eventSource, handler); return tcs.Task; }
  • 79. Awaiting Generic Events public static Task<EventArgs> Event ( this object eventSource, string eventName, Predicate<EventArgs> predicate = null) { var tcs = new TaskCompletionSource<EventArgs>(); var type = eventSource.GetType (); var ev = type.GetEvent (eventName); EventHandler handler; handler = delegate (object sender, EventArgs e) { if (predicate == null || predicate (e)) { ev.RemoveEventHandler (eventSource, handler); tcs.SetResult (e); } }; ev.AddEventHandler (eventSource, handler); return tcs.Task; }
  • 80. button.TouchUpInside += async delegate { var project = await ChooseProject (); project.DoSomethingMindBlowing (); }
 AwaitingView Controllers
  • 81. Task<Project> ChooseProject ()
 {
 var tcs = new TaskCompletionSource<Project> ();
 
 var vc = new ChooseProjectViewController (projs);
 vc.Completed += (s, e) => {
 DismissViewController (true, null);
 tcs.SetResult (vc.Project);
 };
 
 PresentViewController (vc, true, null);
 
 return tcs.Task;
 }
 AwaitingView Controllers
  • 82. Task<Project> ChooseProject ()
 {
 var tcs = new TaskCompletionSource<Project> ();
 
 var vc = new ChooseProjectViewController (projs);
 vc.Completed += (s, e) => {
 DismissViewController (true, null);
 tcs.SetResult (vc.Project);
 };
 
 PresentViewController (vc, true, null);
 
 return tcs.Task;
 }
 AwaitingView Controllers
  • 83. Task<Project> ChooseProject ()
 {
 var tcs = new TaskCompletionSource<Project> ();
 
 var vc = new ChooseProjectViewController (projs);
 vc.Completed += (s, e) => {
 DismissViewController (true, null);
 tcs.SetResult (vc.Project);
 };
 
 PresentViewController (vc, true, null);
 
 return tcs.Task;
 }
 AwaitingView Controllers
  • 84. Task<Project> ChooseProject ()
 {
 var tcs = new TaskCompletionSource<Project> ();
 
 var vc = new ChooseProjectViewController (projs);
 vc.Completed += (s, e) => {
 DismissViewController (true, null);
 tcs.SetResult (vc.Project);
 };
 
 PresentViewController (vc, true, null);
 
 return tcs.Task;
 }
 AwaitingView Controllers
  • 85. if (await Ask ("Archive", "Cancel") == 0) { await Archive (); }
 Awaiting Dialogs
  • 86. Task<int> Ask (params string[] answers)
 {
 var tcs = new TaskCompletionSource<int> ();
 
 var sheet = new UIActionSheet ();
 foreach (var a in answers) sheet.AddButton (a);
 sheet.CancelButtonIndex = answers.Length - 1;
 
 sheet.Clicked += (s, e) => {
 tcs.SetResult (e.ButtonIndex);
 };
 
 sheet.ShowFrom (View.Bounds, View, true);
 
 return tcs.Task;
 }
 Awaiting Dialogs
  • 87. Task<int> Ask (params string[] answers)
 {
 var tcs = new TaskCompletionSource<int> ();
 
 var sheet = new UIActionSheet ();
 foreach (var a in answers) sheet.AddButton (a);
 sheet.CancelButtonIndex = answers.Length - 1;
 
 sheet.Clicked += (s, e) => {
 tcs.SetResult (e.ButtonIndex);
 };
 
 sheet.ShowFrom (View.Bounds, View, true);
 
 return tcs.Task;
 }
 Awaiting Dialogs
  • 88. Task<int> Ask (params string[] answers)
 {
 var tcs = new TaskCompletionSource<int> ();
 
 var sheet = new UIActionSheet ();
 foreach (var a in answers) sheet.AddButton (a);
 sheet.CancelButtonIndex = answers.Length - 1;
 
 sheet.Clicked += (s, e) => {
 tcs.SetResult (e.ButtonIndex);
 };
 
 sheet.ShowFrom (View.Bounds, View, true);
 
 return tcs.Task;
 }
 Awaiting Dialogs
  • 89. Task<int> Ask (params string[] answers)
 {
 var tcs = new TaskCompletionSource<int> ();
 
 var sheet = new UIActionSheet ();
 foreach (var a in answers) sheet.AddButton (a);
 sheet.CancelButtonIndex = answers.Length - 1;
 
 sheet.Clicked += (s, e) => {
 tcs.SetResult (e.ButtonIndex);
 };
 
 sheet.ShowFrom (View.Bounds, View, true);
 
 return tcs.Task;
 }
 Awaiting Dialogs
  • 90. Task<int> Ask (params string[] answers)
 {
 var tcs = new TaskCompletionSource<int> ();
 
 var sheet = new UIActionSheet ();
 foreach (var a in answers) sheet.AddButton (a);
 sheet.CancelButtonIndex = answers.Length - 1;
 
 sheet.Clicked += (s, e) => {
 tcs.SetResult (e.ButtonIndex);
 };
 
 sheet.ShowFrom (View.Bounds, View, true);
 
 return tcs.Task;
 }
 Awaiting Dialogs
  • 91. And more... Chaining Animations Multi-gesture Recognition Autonomous Services ...
  • 94. TaskScheduler Think of it as a Thread it’s not though
  • 95. TaskScheduler Think of it as a Thread it’s not though but close enough
  • 96. var tweets = await client.GetTweetsAsync (); countLabel.Text = tweets.Count;
  • 97. var tweets = await client.GetTweetsAsync (); countLabel.Text = tweets.Count; client.GetTweetsAsync ().ContinueWith ( t => { if (t.IsFaulted) throw new AggregateException (t.Exception); countLabel.Text = tweets.Count; }, TaskScheduler.FromCurrentSynchronizationContext ());
  • 99. var tweets = await client.GetTweetsAsync (). ConfigureAwait (false); countLabel.Text = tweets.Count;
  • 100. client.GetTweetsAsync ().ContinueWith ( t => { if (t.IsFaulted) throw new AggregateException (t.Exception); countLabel.Text = tweets.Count; }); var tweets = await client.GetTweetsAsync (). ConfigureAwait (false); countLabel.Text = tweets.Count; Does not synchronize with the UI
  • 103. CancellationToken public Task LaunchTheRockets ( CancellationToken token);
  • 104. CancellationTokenSource var cts = new CancellationTokenSource (); control.LaunchTheRockets (cts.Token);
  • 105. CancellationTokenSource var cts = new CancellationTokenSource (); control.LaunchTheRockets (cts.Token); // OMG, Cancel the rockets! cts.Cancel ();
  • 106. Why Async? Why Await? Tour of System.Threading.Tasks with Real-world Uses of Await Fak-world Uses of Await Interlude
  • 108. Adventure Player IConsole 1 interface IConsole { TextReader In { get; } TextWriter Out { get; } }

  • 109. Adventure public static void Main (string[] args) { var console = new ConsoleConsole (); var map = Map.GenerateRandom (); var player = new Player( map.StartingLocation, console); player.Play ().Wait (); }

  • 110. Adventurepublic async Task Play () { while (true) { // Print the status await console.Out.WriteLineAsync (Location.Description); await console.Out.WriteLineAsync (Status); // Read the command from the user var command = await console.In.ReadLineAsync (); if (!string.IsNullOrWhiteSpace (command)) { // Execute it var result = Execute (command); // Print the result await console.Out.WriteLineAsync (result); } } }

  • 111. Why Async? Why Await? Tour of System.Threading.Tasks with Real-world Uses of Await Fak-world Uses of Await
  • 113. async Task EnterCode () { // Must Tap buttons in the order 4, 2, 3, 3 await button4.Tapped (); await button2.Tapped (); await button3.Tapped (); await button3.Tapped (); // They get access RevealSecretUI (); } Recognizing Asynchronous Events
  • 115. Async Tutorial async Task ShowTheUserHowToSearch () { await Tutorial.EnterText (searchField, minLength: 3); await Tutorial.Tap (searchButton); await Tutorial.Congratulate ("Now you know how to search."); }
 http://praeclarum.org/post/45277337108
  • 118. Turn the Web Server Inside Out Instead of waiting for random requests, specify the requests you want in the order you want them.
  • 119. public class StepByStepServer : WebServer { protected override async Task RunSession (WebSession session) { await session.Get ("/"); await session.Out.WriteLineAsync ( "<html><h1>Home</h1><a href='step1'>Next</a></html>"); await session.Get ("/hello"); await session.Out.WriteLineAsync ( "<html><h1>Hello</h1><a href='done'>Finish</a></html>"); await session.Get ("/done"); await session.Out.WriteLineAsync ( "<html><h1>Yay!</h1><a href='/'>Start Over</a></html>"); } } 
 

  • 120. public class CounterServer : WebServer { protected override async Task RunSession (WebSession session) { for (var i = 3; i >= 1; i--) { await session.Get (); await session.Out.WriteAsync (i.ToString ()); } while (true) { await session.Get (); await session.Out.WriteAsync ("Go MonkeySpace!"); } } }

  • 122. class WebConsole : IConsole
  • 123. Adventure on the Web using the same code as the Console
  • 124. public class GameServer : WebServer { Map map; public GameServer (Map map) { this.map = map; } protected override async Task RunSession (WebSession session) { var console = new WebConsole (session); var player = new Player (map.StartingLocation, console); await player.Play (); } }

  • 125. public class GameServer : WebServer { Map map; public GameServer (Map map) { this.map = map; } protected override async Task RunSession (WebSession session) { var console = new WebConsole (session); var player = new Player (map.StartingLocation, console); await player.Play (); } }

  • 126. public class GameServer : WebServer { Map map; public GameServer (Map map) { this.map = map; } protected override async Task RunSession (WebSession session) { var console = new WebConsole (session); var player = new Player (map.StartingLocation, console); await player.Play (); } }

  • 129. Resources Channel 9 - http://channel9.msdn.com Xamarin EvolveVideos - http://xamarin.com/evolve/2013 Ask Jon Skeet