Task in C#
Task in C#
- Task represents the execution and completion of an asynchronous operation. It can be used to encapsulate an asynchronous operation, allowing it to execute without blocking the main thread and retrieve the result after completion.
static void Main(string[] args)
{
MyFun();
Console.Read();
}
static void MyFun()
{
// var firstTask = new Task<int>(() => TaskMethod("First Task", 3));
Task t1 = new Task<int>(() => MyMethod("write"));
Task t2 = Task<int>.Factory.StartNew(() => MyMethod("red")); // This starts automatically
t1.Start(); // This must be started manually
}
static int MyMethod(string name)
{
Console.WriteLine($"I am {name}");
return 0;
}
- Example:
UseMethodAsync()submits the operation to the thread pool viaTask.Runand usesawaitto wait for completion and retrieve the result.
static async Task<int> LongOperationAsync()
{
// Simulate a time-consuming operation
await Task.Delay(1000);
return 42; // Assume this is the result of the long operation
}
static async Task UseMethodAsync()
{
int result = await Task.Run(() => LongOperationAsync());
Console.WriteLine($"Operation result: {result}");
}
- Parallel tasks with Task.WhenAll: Process multiple tasks in parallel and wait for all to complete before proceeding.
static async Task ParallelProcessingAsync()
{
Task<int> task1 = Task.Run(() => LongOperationAsync());
Task<int> task2 = Task.Run(() => LongOperationAsync());
Task<int> task3 = Task.Run(() => LongOperationAsync());
// Wait for all tasks to complete
await Task.WhenAll(task1, task2, task3);
// Continue processing results
Console.WriteLine("All tasks completed");
}
- Cancellation in Tasks
static async Task<int> LongOperationWithCancellationAsync(CancellationToken cancellationToken)
{
await Task.Delay(1000, cancellationToken);
return 42;
}
static async Task MyMethodWithCancellationAsync()
{
using (var cts = new CancellationTokenSource())
{
Task<int> task = Task.Run(() => LongOperationWithCancellationAsync(cts.Token));
// Simulate timeout logic; in practice, other conditions may trigger
cts.CancelAfter(1000); // Cancel after 1000ms (1 second)
try
{
int result = await task;
Console.WriteLine($"Operation result: {result}");
}
catch (OperationCanceledException)
{
Console.WriteLine("Operation was canceled");
}
}
}
- Error handling in Tasks
static async Task<int> OperationWithFailAsync()
{
// Simulate an operation that may fail
await Task.Delay(100);
throw new InvalidOperationException("Operation failed");
}
static async Task HandleTaskAsync()
{
try
{
await Task.Run(() => OperationWithFailAsync());
}
catch (Exception ex)
{
Console.WriteLine($"Error occurred: {ex.Message}");
}
}
-
Continuation with Task.ContinueWith: Allows specifying another task to run after the first task completes.
a.
ContinueWith()waits until the first task's status reachesIsCompletedbecauseTaskContinuationOptions.OnlyOnRanToCompletionis used.
static int TaskMethod(string name, int seconds)
{
Console.WriteLine("Task {0} is running. Thread id {1}, Is thread pool: {2}", name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
Thread.Sleep(TimeSpan.FromSeconds(seconds));
return 60 * seconds;
}
static void Main(string[] args)
{
var firstTask = new Task<int>(() => TaskMethod("First Task", 3));
firstTask.ContinueWith(t => Console.WriteLine("First Task Result: {0}.. Thread id {1}, Is thread pool: {2}", t.Result, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread), TaskContinuationOptions.OnlyOnRanToCompletion);
firstTask.Start();
// Main thread work
Console.WriteLine("Back Work: Thread id {0}, Is thread pool: {1}", Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
Console.Read();
}
Note: The main thread is not blocked.
b. Example with two tasks and continuation options.
static int TaskMethod(string name, int seconds)
{
Console.WriteLine("Task {0} is running. Thread id {1}, Is thread pool: {2}", name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
Thread.Sleep(TimeSpan.FromSeconds(seconds));
return 60 * seconds;
}
static void Main(string[] args)
{
Console.WriteLine("Main thread id {0}, Is thread pool: {1}", Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
var firstTask = new Task<int>(() => TaskMethod("First Task", 3));
var secondTask = new Task<int>(() => TaskMethod("Second Task", 2));
firstTask.ContinueWith(t => Console.WriteLine("First Task Result: {0}.. Thread id {1}, Is thread pool: {2}", t.Result, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread), TaskContinuationOptions.OnlyOnRanToCompletion);
firstTask.Start();
secondTask.Start();
// Comment out the next line to see different behavior:
// Thread.Sleep(TimeSpan.FromSeconds(4)); // Wait for firstTask, secondTask and continuations to complete.
secondTask.ContinueWith(t => Console.WriteLine("Second Task Result: {0}.. Thread id {1}, Is thread pool: {2}", t.Result, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread), TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.ExecuteSynchronously);
// Main thread work
Console.Read();
}
If the Thread.Sleep is comented out, the main thread ends early, and secondTask's continuation runs on the thread pool. If uncommented, the main thread sleeps for 4 seconds, allowing both tasks to complete, and due to ExecuteSynchronously, the continuation of secondTask runs on the main thread.
- Task.WhenAny and Task.WhenAll
static async Task<string> DoMethod(int time, string name = "wo")
{
Console.WriteLine($"{name} come in.");
await Task.Delay(TimeSpan.FromMilliseconds(time));
return string.Format("{0} have done this work, time is {1}", name, time);
}
static async Task TimeOutMethod(int needTimeOut)
{
Console.WriteLine($"needTimeOut={needTimeOut}");
var t = new Stopwatch();
t.Start(); // Start timing
var timeOutTask = Task.Run(() => Task.Delay(150).ContinueWith(_ => "Task timeOutTask finished after 150 seconds")); // Create a timeout task.
var doing = DoMethod(needTimeOut); // The task to execute.
var task = await Task.WhenAny(timeOutTask, doing); // Return as soon as either completes
Console.WriteLine(task.Result);
t.Stop();
Console.WriteLine("used time: " + t.Elapsed.TotalMilliseconds);
}
static void Main(string[] args)
{
TimeOutMethod(50);
TimeOutMethod(500);
Console.Read();
}
Explanation: With parameter 50, DoMethod completes first, returning "wo have done this work, time is 50". With parameter 500, timeOutTask completes first, returning "Task timeOutTask finished after 150 seconds".
/// <summary>
/// Execute multiple tasks together, collect results, and process them.
/// </summary>
static async Task Tasks()
{
var t = new Stopwatch();
t.Start(); // Start timing
var list = new List<string>();
var t1 = DoMethod(1000, "1000");
var t2 = DoMethod(1500, "1500");
var t3 = DoMethod(1200, "1200");
var tasks = new[] { t1, t2, t3 };
// Collect results
var process = tasks.Select(async tt =>
{
var result = await tt;
list.Add(result);
});
// Wait for all tasks to complete before using results
await Task.WhenAll(process);
foreach (var i in list)
{
Console.WriteLine(i);
}
t.Stop();
Console.WriteLine("used time: " + t.Elapsed.TotalMilliseconds);
}
static void Main(string[] args)
{
Tasks();
Console.Read();
}
This waits for all tasks (the shorter ones finish earlier but results are collected after all complete).