Axa Assurance Maroc - Insurer Innovation Award 2024
Windows Phone 8 - 3.5 Async Programming
1. Oliver Scheer
Senior Technical Evangelist
Microsoft Deutschland
http://the-oliver.com
Async and Await
Programming on Windows
Phone 8
await
async
2. Agenda
3/17/2014Microsoft confidential2
async and await in C#5 Task Programming Model
How awaitable objects work
The new way to do parallel processing
Replacing BackgroundWorker with async
Learn why you’ll never use Thread or Threadpool again!
3. • Windows Phone 7.1 Base Class Libraries used .NET 4.0 patterns to support asynchronous
programming
• Async programming model: BeginXYZ, EndXYZ methods
• Example: HttpWebRequest BeginGetResponse and EndGetResponse methods
• Event async pattern: Setup a Completed event handler, then call XYZAsync() to start operation
• Example: WebClient DownloadStringAsync method and DownloadStringCompleted event
• Windows Phone 8 includes many WinRT APIs
• Any API that potentially takes more than 50ms to complete is exposed as an asynchronous
method using a new pattern: Task Programming Model
• Asynchronous programming is a first class citizen of WinRT, used for File I/O, Networking etc
• Task-based programming is becoming the way to write asynchronous code
• Many new APIs in Windows Phone 8 now and in the future will offer only a Task-based API
Async Methods and Task Programming Model
3/17/2014Microsoft confidential3
4. Keeping UI Fast and Fluid
Comparing blocking File I/O using WP7.1 with TPM File I/O in WP8
3/17/2014Microsoft confidential4
TIME UI Thread
var isf = IsolatedStorageFile.GetUserStoreForApplication();
using (var fs = new IsolatedStorageFileStream(
"CaptainsLog.store", FileMode.Open, isf))
{
StreamReader reader = new StreamReader(fs);
theData = reader.ReadToEnd();
reader.Close();
};
5. StorageFile storageFile = await
Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(
new Uri("ms-appdata:///local/CaptainsLog.store "));
Stream readStream = await StorageFile.OpenStreamForReadAsync();
using (StreamReader reader = new StreamReader(readStream))
{
theData = await reader.ReadToEndAsync();
}
Keeping UI Fast and Fluid
Comparing blocking File I/O using WP7.1 with TPM File I/O in WP8
3/17/2014Microsoft confidential5
TIME UI Thread
6. Making Asynchronous Code Look Synchronous
3/17/2014Microsoft confidential6
private async Task<string> LoadFromLocalFolderAsync()
{
StorageFile storageFile = await
Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(
new Uri("ms-appdata:///local/CaptainsLog.store "));
Stream readStream = await storageFile.OpenStreamForReadAsync();
using (StreamReader reader = new StreamReader(readStream))
{
theData = await reader.ReadToEndAsync();
}
}
Original
Context ThreadpoolTIME
7. Simpler for Developers to Write Asynchronous Code
3/17/2014
Microsoft confidential7
private async void SomeMethod()
{
…
string theData = await LoadFromLocalFolderAsync();
TextBox1.Text = theData;
…
}
private async Task<string> LoadFromLocalFolderAsync()
{
...
}
All Async methods must
return void, Task or
Task<TResult>
Caller can use the await
keyword to pause until the
async operation has
completed execution on a
Threadpool thread
It automatically marshals
back to the originating
context, so no need to
use the Dispatcher to set
UI objects on the UI
thread
All methods that contain
calls to awaitables must
be declared using the
async keyword
When the async code
completes , it ‘calls back’
and resumes where it left
off, passing back the
return value
8. • Marking a method with the async keyword causes the C# or Visual Basic compiler to
rewrite the method’s implementation using a state machine
• Using this state machine the compiler can insert points into the method at which the
method can suspend and resume its execution without blocking a thread
• These points are inserted only where you explicitly use the await keyword
• When you await an asynchronous operation that’s not yet completed:
• Compiler packages up all the current state of the calling method and preserves it on the heap
• Function returns to the caller, allowing the thread on which it was running to do other work
• When the awaited operation later completes, the method’s execution resumes using the
preserved state
Compiler Transformations
3/17/2014Microsoft confidential8
10. private async void SomeMethod()
{
await LoadFromLocalFolderAsync();
[Preserve state on heap]
}
[Calling thread free to do other work]
Freeing Up the Calling Thread
3/17/2014Microsoft confidential10
[Calling thread free to do other work]
[Calling thread free to do other work]
[Calling thread free to do other work]
11. {
[Restore Context]
string theData = [Result from LoadFromLocalFolder()]
TextBox1.Text = theData;
}
private async void SomeMethod()
{
await LoadFromLocalFolder();
[Preserve state on heap]
}
[Calling thread free to do other work]
Freeing Up the Calling Thread
3/17/2014Microsoft confidential11
[Calling thread free to do other work]
[Calling thread free to do other work]
[Calling thread free to do other work]
12. • Error Handling is simpler
• Just use try…catch around the async code, same as with synchronous code
• Exceptions thrown while code is executing asynchronously are surfaced back on the calling thread
private async void SomeMethod()
{
try
{
string theData = await LoadFromLocalFolder();
TextBox1.Text = theData;
}
catch (Exception ex)
{
// An exception occurred from the async operation
}
}
Error Handling
3/17/2014Microsoft confidential12
13. • No, you can call async methods without await
• Called method still executes on background thread
• The calling thread does not wait for the result
• Only feasible for async methods that return void or Task, not Task<TResult>
• Intellisense warns you when you do this
Must I use await with async methods?
3/17/2014Microsoft confidential13
16. • If you have some long-running code that you want to execute on a background thread, the
BackgroundWorker class is a good solution
• Still supported in Windows Phone 8!
• Supports Cancellation and Progress reports
• You can get the same behaviour using Tasks
Executing Code on a Background Thread
3/17/2014Microsoft confidential16
17. private void LaunchTaskButton_Click(object sender, RoutedEventArgs e)
{
BackgroundWorker bgw = new BackgroundWorker();
bgw.RunWorkerCompleted += ((s, a) =>
MessageBox.Show("BackgroundWorker has completed, result: " + (int)a.Result)
);
bgw.DoWork += ((s, a) =>
{
// Simulate some long running work
Thread.Sleep(5000);
// Return the result
a.Result = 1234;
});
// Now start execution
bgw.RunWorkerAsync();
}
BackgroundWorker
3/17/2014Microsoft confidential17
18. private async void LaunchTaskButton_Click(object sender, RoutedEventArgs e)
{
int result = await Task.Factory.StartNew<int>(() =>
{
// Simulate some long running work
Thread.Sleep(5000);
// Return the result
return 4321;
}
);
MessageBox.Show("BackgroundWorker has completed, result is: " + result);
}
Task Equivalent
3/17/2014Microsoft confidential18
19. BackgroundWorker bgw = new BackgroundWorker();
bgw.WorkerReportsProgress = true;
bgw.RunWorkerCompleted += ((s, a) => MessageBox.Show("BackgroundWorker has completed, result: " + (int)a.Result));
bgw.ProgressChanged += ((s, a) => {
// Progress Indicator value must be between 0 and 1
SystemTray.GetProgressIndicator(this).Value = (double)a.ProgressPercentage/100.0; });
bgw.DoWork += ((s, a) => {
// Simulate some long running work
for (int i = 0; i < 10; i++)
{
Thread.Sleep(500);
// Report progress as percentage completed
bgw.ReportProgress(i * 10);
}
a.Result = 1234; // Return the result
});
// Now start execution
bgw.RunWorkerAsync();
BackgroundWorker with Progress Reporting
3/17/2014Microsoft confidential19
20. IProgress<int> progressReporter = new Progress<int>((percentComplete) =>
// Progress Indicator value must be between 0 and 1
SystemTray.GetProgressIndicator(this).Value = (double)percentComplete / 100.0 );
int result = await Task.Factory.StartNew<int>(() =>
{
// Simulate some long running work
for (int i = 0; i < 10; i++)
{
Thread.Sleep(500);
// Report progress as percentage completed
progressReporter.Report(i * 10);
}
// Return the result
return 4321;
} );
MessageBox.Show("BackgroundWorker has completed, result is: " + result);
Task with Progress Reporting
3/17/2014Microsoft confidential20
21. BackgroundWorker bgw = new BackgroundWorker();
bgw.WorkerReportsProgress = true;
bgw.WorkerSupportsCancellation = true;
bgw.RunWorkerCompleted += ((s, a) =>
{
if (a.Cancelled)
MessageBox.Show("BackgroundWorker was cancelled");
else
MessageBox.Show("BackgroundWorker has completed, result: " + (int)a.Result);
} );
bgw.ProgressChanged += ((s, a) => { ... });
bgw.DoWork += ((s, a) =>
{
// Simulate some long running work
for (int i = 0; i < 10; i++)
{
Thread.Sleep(500);
// Report progress as percentage completed
bgw.ReportProgress(i * 10);
// Have we been cancelled?
BackgroundWorker with Cancellation
3/17/2014Microsoft confidential21
22. bgw.DoWork += ((s, a) =>
{
// Simulate some long running work
for (int i = 0; i < 10; i++)
{
Thread.Sleep(500);
// Report progress as percentage completed
bgw.ReportProgress(i * 10);
// Have we been cancelled?
if (bgw.CancellationPending)
BackgroundWorker with Cancellation
3/17/2014Microsoft confidential22
23. var cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = cancellationTokenSource.Token;
try
{
int result = await Task.Factory.StartNew<int>(() =>
{
// Simulate some long running work
for (int i = 0; i < 10; i++)
{
Thread.Sleep(500);
// Have we been cancelled?
cancellationToken.ThrowIfCancellationRequested();
}
return 4321; // Return the result
}, cancellationToken);
MessageBox.Show("BackgroundWorker has completed, result is: " + result);
}
catch (OperationCanceledException ex) {
MessageBox.Show("Task BackgroundWorker was cancelled");
}
Task with Cancellation
3/17/2014Microsoft confidential23
24.
25. • C#5 and VB.NET add first-class support for asynchronous programming
• Methods that return void, Task or Task<TResult> can be called using the await modifier
• The await modifier causes the caller to suspend execution and wait for completion of the
async task
• When complete, the return result and any exceptions are automatically marshalled back to
the originating context
• Execution continues where it left off – makes async code appear synchronous!
• Methods that make calls using await must themselves be marked with the async modifier
Summary
3/17/2014