Read the syntax
Task represents an operation that may complete later; Task<T> also carries a result. await observes completion and propagates failures.
Task.Run schedules work on the thread pool and is useful for CPU-bound work in appropriate contexts. Task.CompletedTask and Task.FromResult wrap already-completed work without starting a new thread.
Syntax
Task<T> task = SomeAsyncMethod();Examples
Creating and Running a Task
Starting work on a separate task and awaiting its completion.
Task<int> CalculateAsync()
{
return Task.Run(() =>
{
Thread.Sleep(500); // simulate CPU-bound work
return 6 * 7;
});
}
int result = await CalculateAsync();
Console.WriteLine(result); // 42- Starting work on a separate task and awaiting its completion.
- Task represents an operation that may complete later; Task<T> also carries a result. await observes completion and propagates failures.
- Task.Run performs the calculation in a thread-pool task after a simulated blocking wait. Await retrieves 42 and the final line prints it.
Task Status and Properties
Inspecting a task's state without necessarily awaiting it immediately.
Task<int> task = Task.Run(() =>
{
Thread.Sleep(300);
return 100;
});
Console.WriteLine(task.IsCompleted); // timing-dependent
int result = await task;
Console.WriteLine(task.IsCompleted); // true
Console.WriteLine(result); // 100- Inspecting a task's state without necessarily awaiting it immediately.
- Task represents an operation that may complete later; Task<T> also carries a result. await observes completion and propagates failures.
- The first IsCompleted is timing-dependent and may be either bool value. After await it is True, and the result printed is 100.
Task.CompletedTask and Task.FromResult
Returning an already-completed task, useful for satisfying an async interface without real async work.
Task LogAsync(string message)
{
Console.WriteLine(message);
return Task.CompletedTask; // no real async work needed, but interface requires Task
}
Task<int> GetCachedValueAsync(int cached)
{
return Task.FromResult(cached); // wraps an already-known value in a Task
}
await LogAsync("Started");
int value = await GetCachedValueAsync(99);
Console.WriteLine(value);- Returning an already-completed task, useful for satisfying an async interface without real async work.
- Task represents an operation that may complete later; Task<T> also carries a result. await observes completion and propagates failures.
- LogAsync writes Started and returns a completed task. GetCachedValueAsync wraps 99 in an already-completed Task<int>; awaiting it prints 99.
Best practices
- Use Task.Run() specifically for offloading CPU-bound work to a background thread - it is not needed for naturally async I/O operations like HttpClient calls, which are already non-blocking
- Prefer awaiting a Task directly over checking .IsCompleted in a polling loop - awaiting is more efficient and far simpler to reason about
- Use Task.FromResult() or Task.CompletedTask when implementing an async interface method that has no real asynchronous work to do
- Avoid using .Result or .Wait() to synchronously block on a Task - always prefer await, which does not risk deadlocks or block the calling thread
Runtime & versions
.NET runtime. Feature availability depends on the language and runtime version used by your project; consult the official reference below.
C# language reference