Asynchronous
async & await
For I/O-bound code, you await an operation which returns a Task or Task<T> inside of an async method.
public class ContentManagement
{
public string GetContent()
{
Thread.Sleep(2000);
return "content";
}
public async Task<string> GetContentAsync()
{
await Task.Delay(2000);
return "content";
}
}
Synchronous
var content = GetContent();
Asynchronous
var task = GetContentAsync();
...
...
var content = await task;
Or
var content = await GetContentAsync();
Samples
Sample 1
private readonly HttpClient _httpClient = new HttpClient();
downloadButton.Clicked += async (o, e) =>
{
// This line will yield control to the UI as the request
// from the web service is happening.
//
// The UI thread is now free to perform other work.
var stringData = await _httpClient.GetStringAsync(URL);
DoSomethingWithData(stringData);
};
Sample 2
private readonly HttpClient _httpClient = new HttpClient();
[HttpGet]
[Route("DotNetCount")]
public async Task<int> GetDotNetCountAsync()
{
// Suspends GetDotNetCountAsync() to allow the caller (the web server)
// to accept another request, rather than blocking on this one.
var html = await _httpClient.DownloadStringAsync("http://dotnetfoundation.org");
return Regex.Matches(html, @"\.NET").Count;
}
Sample 3
public async Task<User> GetUserAsync(int userId)
{
// Code omitted:
//
// Given a user Id {userId}, retrieves a User object corresponding
// to the entry in the database with {userId} as its Id.
}
public static async Task<IEnumerable<User>> GetUsersAsync(IEnumerable<int> userIds)
{
var getUserTasks = new List<Task<User>>();
foreach (int userId in userIds)
{
getUserTasks.Add(GetUserAsync(userId));
}
return await Task.WhenAll(getUserTasks);
}
Sample 3a
public async Task<User> GetUserAsync(int userId)
{
// Code omitted:
//
// Given a user Id {userId}, retrieves a User object corresponding
// to the entry in the database with {userId} as its Id.
}
public static async Task<User[]> GetUsersAsync(IEnumerable<int> userIds)
{
var getUserTasks = userIds.Select(id => GetUserAsync(id));
return await Task.WhenAll(getUserTasks);
}
Task.Run()
For CPU-bound code, you await an operation which is started on a background thread with the Task.Run method.
Samples
private DamageResult CalculateDamageDone()
{
// Code omitted:
//
// Does an expensive calculation and returns
// the result of that calculation.
}
calculateButton.Clicked += async (o, e) =>
{
// This line will yield control to the UI while CalculateDamageDone()
// performs its work. The UI thread is free to perform other work.
var damageResult = await Task.Run(() => CalculateDamageDone());
DisplayDamage(damageResult);
};
Notes
async methods need to have an await keyword in their body or they will never yield!
"Async" should be added as the suffix of every async method name you write.
async void should only be used for event handlers.
Don't use async wrappers for synchronous methods
Don't wrap asynchronous tasks in another call to Task.Run().
Don't use Task.Run() in the implementation of the method; instead, use Task.Run() to call the method.