C# language feature:
applies to
benefit
how to use
async
to designate asynchronous method.Task
, void
(send and forget) and Task<T>
(if object/data needed to proceed).await
within the asynchronous method to “yield control” to the caller. i.e. caller execution continues. The asynchronous method execution will be “scheduled” to be completed by the OS.Task.Run
(spawn of seperate thread), for I/O-bound code DO NOT USE Task.Run
.important
async
methods must have await
keyword.
Only use async void
for event handlers.
Calling code awaiting tasks should be “non-blocking”.
Asynchronous code should minimize dependencies on state.caution
example:
public class Asynchronous_methods_Example {
// 1) modify method with async 2) return Task<T> (Object needed to proceed only if awaited on from caller)
async Task<int> StartCPUTasksAsync()
{
System.Console.WriteLine("Before StartCPUTasks:");
Random x = new Random();
List<string> idList = new List<string> { "A", "B", "C", "D" };
IEnumerable<Task> cpuTasks = idList.Select(id => CpuTaskAsync(id, x.Next(2000, 5000)));
await Task.WhenAll(cpuTasks); // 3) starts all cpu tasks and yeild to caller of StartCPUTasksAsync
System.Console.WriteLine("After StartCPUTasks:"); // note: await Task.WhenAll above prevents execution of this until all io tasks complete
return idList.Count;
}
Task CpuTaskAsync(string taskid, int milliseconds = 1000)
{
// 4) use Task.Run to spawn thread for CPU bound task
return Task.Run(() =>
{
Console.WriteLine(taskid + ": (" + milliseconds + ") CpuTaskAsync start:" + System.DateTime.Now.ToString());
System.Threading.Thread.Sleep(milliseconds);
Console.WriteLine(taskid + ": CpuTaskAsync end:" + System.DateTime.Now.ToString());
}
);
}
// 1) modify method with async 2) return Task<T> (caller is able to force waiting for Object using await)
async Task<int> StartIOTasksAsync()
{
System.Console.WriteLine("Before StartIOTasksAsync:");
List<string> UriList = new List<string> { "https://microsoft.com", "http://apple.com", "https://code-sage.com" };
IEnumerable<Task> ioTasks = UriList.Select(uri => IoTaskAsync(uri));
await Task.WhenAll(ioTasks); // starts all requests up to the "await GetByteArrayAsync statement in IoTaskAsync"
System.Console.WriteLine("After StartIOTasksAsync:"); // note: await Task.WhenAll above prevents execution of this until all IoTaskAsync(s) complete
return UriList.Count;
}
// 1) modify method with async that returns Task, void (send and forget)
async Task IoTaskAsync(string URI)
{
System.Console.WriteLine("IoTaskAsync start:" + URI);
HttpClient client = new HttpClient();
byte[] response = await client.GetByteArrayAsync(URI); // 2) yield control to caller (i.e. StartIOTasksAsync above starts next web request)
System.Console.WriteLine("IoTaskAsync done:" + URI); // note: resumed by OS when response available (because of the await state above
}
// 1) modify method with async that returns Task, void (send and forget)
public async void StartTasksNoBlockingAtAll()
{
System.Console.WriteLine("StartTasksNoBlockingAtAll start");
StartCPUTasksAsync(); //note: without await this async method returns before all cputasks complete
StartIOTasksAsync(); //note: without await this async method returns before all io tasks complete
System.Console.WriteLine("StartTasksNoBlockingAtAll ends"); // this will displayed before either of the above "after cpu or io tasks" messages finish
}
// 1) modify method with async 2) return Task<T> (caller is able to force waiting for Object using await)
public async Task<int> StartTasksinGroupsandWaitAsync()
{
System.Console.WriteLine("StartTasksinGroupsandWaitAsync start");
int x = await StartCPUTasksAsync(); // note: this async will wait for all cputask initiated with this call
int y = await StartIOTasksAsync(); //note: this async method returns before all io tasks complete
System.Console.WriteLine("StartTasksinGroupsandWaitAsync ends"); // this will displayed before either of the above "after cpu or io tasks" messages finish
return x+y;
}
}