Author: Vladimir Khorikov, www.eastbanctech.com
Async/await was a flagman feature in the C# 5 release. It is quite powerful in that it allows you to easily introduce asynchronous programming model into your code base.
On the other hand, there are quite a few pitfalls programmers usually run into when they start using it in practice.
From this presentation, you will learn what those pitfalls are and how to avoid them. It is intended for developers with intermediate level of C# experience.
6. Async control flow
public static async Task<string> GetAsync()
{
var client = new HttpClient();
var response = await client.GetAsync("http://google.com"); // 1
if (!response.IsSuccessStatusCode)
return null;
return await response.Content.ReadAsStringAsync(); // 2
}
7. What is the difference between the two?
public static async Task<HttpResponseMessage> ReadAsync() {
var client = new HttpClient();
return await client.GetAsync("http://google.com");
}
public static Task<HttpResponseMessage> ReadAsync() {
var client = new HttpClient();
return client.GetAsync("http://google.com");
}
8. What is the difference between the two?
public static async Task<HttpResponseMessage> ReadAsync() {
var client = new HttpClient();
throw new Exception();
return await client.GetAsync("http://google.com");
}
public static Task<HttpResponseMessage> ReadAsync() {
var client = new HttpClient();
throw new Exception();
return client.GetAsync("http://google.com");
}
private static void MainMethod() {
Task<HttpResponseMessage> task = ReadAsync();
HttpResponseMessage message = task.Result;
}
9. What will happen to the exception?
private static void MainMethod() {
try {
ReadAsync();
}
catch (Exception ex) {
Console.WriteLine(ex.Message);
}
}
public static async Task ReadAsync() {
var client = new HttpClient();
var message = await client.GetAsync("http://google.com");
throw new Exception();
}
.Wait()
10. Key Points
• Exceptions generated inside a state machine don’t behave the same way
as exceptions in sync methods
11. What will happen to the exception?
private static void MainMethod() {
try {
ReadAsync();
}
catch (Exception ex) {
Console.WriteLine(ex.Message);
}
}
public static async void ReadAsync() {
var client = new HttpClient();
var message = await client.GetAsync("http://google.com");
throw new Exception();
}
12. Key Points
• Exceptions generated inside a state machine don’t behave the same
ways as usual exceptions
• Exceptions in async void methods are dispatched directly to the UI
thread
13. Key Points
• Exceptions generated inside a state machine don’t behave the same
ways as usual exceptions
• Exceptions in async void methods are dispatched directly to the UI
thread
• Don’t use async void methods anywhere except top-level event handlers
14. No need to sync access to UI elements
private async void btnRead_Click(object sender, EventArgs e)
{
btnRead.Enabled = false;
using (var fs = new FileStream("1.txt", FileMode.Open))
using (var sr = new StreamReader(fs))
{
Content = await sr.ReadToEndAsync();
}
btnRead.Enabled = true;
}
15. Before the Async await feature
if (btnRead.InvokeRequired)
{
btnRead.Invoke((Action)(() => btnRead.Enabled = false));
}
else
{
btnRead.Enabled = false;
}
16. No need to sync access to UI elements
private async void btnRead_Click(object sender, EventArgs e)
{
btnRead.Enabled = false;
using (var fs = new FileStream("1.txt", FileMode.Open))
using (var sr = new StreamReader(fs))
{
Content = await sr.ReadToEndAsync()
}
btnRead.Enabled = true;
}
.ConfigureAwait(true);
20. Key Points
• Exceptions generated inside a state machine don’t behave the same
ways as usual exceptions
• Exceptions in async void methods are dispatched directly to the UI
thread
• Don’t use async void methods anywhere except top-level event handlers
• When building a 3rd party library, always put ConfigureAwait(false) in
your async methods
21. CPU-bound vs IO-bound work
• CPU-bound work: some calculations; work performed by the CPU
• IO-bound work: work performed by external, non-CPU devices
22. CPU-bound vs IO-bound work
private async void button1_Click(object sender, EventArgs e)
{
btnCalculate.Enabled = false;
double pi = await Task.Run(() => CalculatePi()); // CPU-bound work
btnCalculate.Enabled = true;
}
public async void button1_Click(object sender, EventArgs e)
{
btnLoad.Enabled = false;
var client = new HttpClient();
var page = await client.GetAsync("http://google.com"); // IO-bound work
btnLoad.Enabled = true;
}
23. Key Points
• Exceptions generated inside a state machine don’t behave the same
ways as usual exceptions
• Exceptions in async void methods are dispatched directly to the UI
thread
• Don’t use async void methods anywhere except top-level event handlers
• When building a 3rd party library, always put ConfigureAwait(false) in
your async methods
• Don’t conflate IO-bound and CPU-bound work
24. Don’t conflate IO-bound and CPU-bound work
private Task<string> ReadFileAsync()
{
return Task.Run(() => // 1
{
using (var fs = new FileStream("1.txt", FileMode.Open))
using (var sr = new StreamReader(fs))
{
return sr.ReadToEnd(); // 2
}
});
}
25. Don’t conflate IO-bound and CPU-bound work
private async Task<string> ReadFileAsync()
{
using (var fs = new FileStream("1.txt", FileMode.Open))
using (var sr = new StreamReader(fs))
{
return await sr.ReadToEndAsync();
}
}
26. Key Points
• Exceptions generated inside a state machine don’t behave the same
ways as usual exceptions
• Exceptions in async void methods are dispatched directly to the UI
thread
• Don’t use async void methods anywhere except top-level event handlers
• When building a 3rd party library, always put ConfigureAwait(false) in
your async methods
• Don’t conflate IO-bound and CPU-bound work