windows phone 8 - 3.5 async programming
TRANSCRIPT
Oliver Scheer
Senior Technical Evangelist
Microsoft Deutschland
http://the-oliver.com
Async and Await Programming on Windows Phone 8
await
async
04/11/2023Microsoft confidential2
Agenda
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!
04/11/2023Microsoft confidential3
•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
04/11/2023Microsoft confidential4
Keeping UI Fast and FluidComparing blocking File I/O using WP7.1 with TPM File I/O in WP8
TIMEUI 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();
};
04/11/2023Microsoft confidential5
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 FluidComparing blocking File I/O using WP7.1 with TPM File I/O in WP8
TIMEUI Thread
04/11/2023Microsoft confidential6
Making Asynchronous Code Look Synchronous
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
Simpler for Developers to Write Asynchronous Code
04/11/2023
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
04/11/2023Microsoft confidential8
•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
04/11/2023Microsoft confidential9
private async void SomeMethod()
{
string theData = await LoadFromLocalFolderAsync();
TextBox1.Text = theData;
}
Freeing Up the Calling Thread
04/11/2023Microsoft confidential10
private async void SomeMethod()
{
await LoadFromLocalFolderAsync();
[Preserve state on heap]
}
[Calling thread free to do other work]
Freeing Up the Calling Thread
[Calling thread free to do other work]
[Calling thread free to do other work]
[Calling thread free to do other work]
04/11/2023Microsoft confidential11
{
[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
[Calling thread free to do other work]
[Calling thread free to do other work]
[Calling thread free to do other work]
04/11/2023Microsoft confidential12
• 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
04/11/2023Microsoft confidential13
•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?
Demo 1: async and await
04/11/2023Microsoft confidential15
Replacing BackgroundWorker
04/11/2023Microsoft confidential16
• 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
04/11/2023Microsoft confidential17
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
04/11/2023Microsoft confidential18
• 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
04/11/2023Microsoft confidential19
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
04/11/2023Microsoft confidential20
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
04/11/2023Microsoft confidential21
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
04/11/2023Microsoft confidential22
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)
{
a.Cancel = true;
return;
}
} a.Result = 1234; // Return the result
});
// Now start execution
bgw.RunWorkerAsync();
BackgroundWorker with Cancellation
04/11/2023Microsoft confidential23
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
Demo 2: BackgroundWorker vs Tasks
04/11/2023
• 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
The information herein is for informational purposes only an represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be
interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation.
© 2012 Microsoft Corporation.
All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries.
MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.