C-Sharp | Java | Python | Swift | GO | WPF | Ruby | Scala | F# | JavaScript | SQL | PHP | Angular | HTML
Part 1: We create a Task instance by calling HandleFileAsync. The task starts, and (later in Main) we call Wait() for it to finish.
Part 2: This async method displays a status message, and does some long-running calculations. We use StreamReader and await ReadToEndAsync.
Part 3: We must be careful to call Wait() on the task we want to wait for. Sometimes the wrong Task can be waited on.
Info: Please change the path to a large text file that exists on your computer. Any large text file will do.
C# program that uses async, await, Task
using System;
using System.IO;
using System.Threading.Tasks;
class Program
{
public static void Main()
{
// Part 1: start the HandleFile method.
Task<int> task = HandleFileAsync();
// Control returns here before HandleFileAsync returns.
// ... Prompt the user.
Console.WriteLine("Please wait patiently " +
"while I do something important.");
// Do something at the same time as the file is being read.
string line = Console.ReadLine();
Console.WriteLine("You entered (asynchronous logic): " + line);
// Part 3: wait for the HandleFile task to complete.
// ... Display its results.
task.Wait();
var x = task.Result;
Console.WriteLine("Count: " + x);
Console.WriteLine("[DONE]");
Console.ReadLine();
}
static async Task<int> HandleFileAsync()
{
string file = @"C:\programs\enable1.txt";
// Part 2: status messages and long-running calculations.
Console.WriteLine("HandleFile enter");
int count = 0;
// Read in the specified file.
// ... Use async StreamReader method.
using (StreamReader reader = new StreamReader(file))
{
string v = await reader.ReadToEndAsync();
// ... Process the file data somehow.
count += v.Length;
// ... A slow-running computation.
// Dummy code.
for (int i = 0; i < 10000; i++)
{
int x = v.GetHashCode();
if (x == 0)
{
count--;
}
}
}
Console.WriteLine("HandleFile exit");
return count;
}
}
Output: initial
HandleFile enter
Please wait patiently while I do something important.
Output: continued
HandleFile enter
Please wait patiently while I do something important.
test
You entered (asynchronous logic): test
Output: final
HandleFile enter
Please wait patiently while I do something important.
test
You entered (asynchronous logic): test
HandleFile exit
Count: 1916146
[DONE]
Action: A lambda expression is specified as the argument to Task.Run. This is an action delegate.
ActionAllocate: This method does a slow-running computation. But when run asynchronously, it does not cause the program to freeze.
Result: Many user inputs can be handled while the computation is running. Each Allocate() call finishes at its own pace.
C# program that uses async computation
using System;
using System.Threading.Tasks;
class Program
{
static void Main()
{
while (true)
{
// Start computation.
Example();
// Handle user input.
string result = Console.ReadLine();
Console.WriteLine("You typed: " + result);
}
}
static async void Example()
{
// This method runs asynchronously.
int t = await Task.Run(() => Allocate());
Console.WriteLine("Compute: " + t);
}
static int Allocate()
{
// Compute total count of digits in strings.
int size = 0;
for (int z = 0; z < 100; z++)
{
for (int i = 0; i < 1000000; i++)
{
string value = i.ToString();
size += value.Length;
}
}
return size;
}
}
Output
hello
You typed: hello
good
You typed: good
day
You typed: day
Compute: 588889000
friend
You typed: friend
Compute: 588889000
Compute: 588889000
Compute: 588889000
Compute: 588889000
Here: From Main, we call the Run2Methods() method 10 times. It asynchronously calls GetSum and then MultiplyNegative1.
Tip: MultiplyNegative1 is always called after GetSum. The ContinueWith method runs its code after the method in Task.Run.
C# program that shows ContinueWith method
using System;
using System.Threading.Tasks;
class Program
{
static void Main()
{
// Call async method 10 times.
for (int i = 0; i < 10; i++)
{
Run2Methods(i);
}
// The calls are all asynchronous, so they can end at any time.
Console.ReadLine();
}
static async void Run2Methods(int count)
{
// Run a Task that calls a method, then calls another method with ContinueWith.
int result = await Task.Run(() => GetSum(count))
.ContinueWith(task => MultiplyNegative1(task));
Console.WriteLine("Run2Methods result: " + result);
}
static int GetSum(int count)
{
// This method is called first, and returns an int.
int sum = 0;
for (int z = 0; z < count; z++)
{
sum += (int)Math.Pow(z, 2);
}
return sum;
}
static int MultiplyNegative1(Task<int> task)
{
// This method is called second, and returns a negative int.
return task.Result * -1;
}
}
Output
Run2Methods result: 0
Run2Methods result: -140
Run2Methods result: -204
Run2Methods result: -14
Run2Methods result: -91
Run2Methods result: -55
Run2Methods result: -30
Run2Methods result: 0
Run2Methods result: -5
Run2Methods result: -1
Main: We call BackgroundMethod, then run some important logic in the for-loop every 100 ms.
BackgroundMethod: Contains a local function InnerMethod. We use the Task constructor to create a new Task.
Then: We invoke Task.Start. Finally we await the task—both methods run at the same time.
C# program that uses async, local method, new Task
using System;
using System.Threading.Tasks;
class Program
{
static void Main()
{
// Run a Task in the background.
BackgroundMethod();
// Run this loop in Main at the same time.
for (int i = 0; i < 5; i++)
{
System.Threading.Thread.Sleep(100);
Console.WriteLine("::Main::");
}
}
async static void BackgroundMethod()
{
// Use a local function.
void InnerMethod()
{
while (true)
{
System.Threading.Thread.Sleep(150);
Console.WriteLine("::Background::");
}
}
// Create a new Task and start it.
// ... Call the local function.
var task = new Task(() => InnerMethod());
task.Start();
await task;
}
}
Output
::Main::
::Background::
::Main::
::Background::
::Main::
::Main::
::Background::
::Main::
To fix: Type "await" in front of Task.Run in BackgroundMethod. Note that the program still needs work.
C# program that shows await operator warnings
using System;
using System.Threading.Tasks;
class Program
{
static void Main()
{
BackgroundMethod();
}
async static void BackgroundMethod()
{
Task.Run(() => Console.WriteLine("X"));
}
}
Output
warning CS4014:
Because this call is not awaited, execution of the current method continues before the call is completed.
Consider applying the await operator to the result of the call.
warning CS1998:
This async method lacks await operators and will run synchronously.
Consider using the await operator to await non-blocking API calls, or await Task.Run(...)
to do CPU-bound work on a background thread.
C# program that causes compile-time error
using System;
using System.Threading.Tasks;
class Program
{
static async void Main()
{
}
}
Output
error CS4009: 'Program.Main()': an entry point cannot be marked
with the 'async' modifier
Info: We can call Task.Run, ContinueWith, Wait—we can even run Tasks without async and await.
CancellationToken: We use a CancellationTokenSource with tokens to signal a task should exit early.
Note: An async method will be run synchronously if it does not contain the await keyword.
Task.Start: The first async method call can occur with the Task Start method. This is an instance method.
Also: Event handlers can be used with async methods. This is not currently shown here.
And: With the Task.Run method, we can make code that uses async and await multithreaded.
Important: Other code can execute (even on the same thread) after an asynchronous task has started.
And: Thanks to Andrew Dennison for reviewing the Allocate() method code which had an unnecessary statement.
Quote: The async and await keywords don't cause additional threads to be created. Async methods don't require multithreading because an async method doesn't run on its own thread.
Asynchronous programming: Microsoft Docs