Skip to content

CSharp Async Tasks TaskRun

Joe Care edited this page Dec 22, 2025 · 1 revision

C# Async: Tasks, Task.Run, and Task.Delay

This lesson builds on the basics from CSharp-AsyncAwait-Basics.md and focuses on:

  • Task as the core representation of an asynchronous operation
  • Task.Run for running CPU-bound work on a thread pool thread
  • Task.Delay for non-blocking delays

Related wiki pages:

  • Async basics: CSharp-AsyncAwait-Basics.md (renamed from Lesson03.12.2025.md)
  • General C# topics: CSharpBible.md
  • Libraries and tasks: CSharpBible-Libraries.md
  • MVVM and async commands: CSharpBible-MVVM-Standard.md, CommunityToolkit.MVVM.md

Official documentation:


1. Task and async/await

  • Task represents an ongoing operation that may complete in the future.
  • Task<T> represents an operation that produces a result of type T.
  • async/await is syntax sugar that lets you write asynchronous code in a sequential style.

You typically do not manage custom "events" to make methods awaitable – the compiler generates a state machine from your async method.


2. Example: running work with Task.Run

Use Task.Run for CPU-bound work that should not block the current thread (e.g., the UI thread). For I/O-bound work you usually call naturally async APIs directly, without Task.Run.

using System;
using System.Threading.Tasks;

namespace CSharpAsync
{
    class Program
    {
        static async Task Main(string[] args)
        {
            Console.WriteLine("Starting...");

            try
            {
                string message = "Hello, world!";

                // Run CPU-bound work on a thread pool thread
                await Task.Run(async () =>
                {
                    Console.WriteLine(message);

                    // Non-blocking delay to simulate work
                    await Task.Delay(100); 
                });
            }
            catch (Exception ex)
            {
                Console.WriteLine($"An error occurred: {ex}");
            }

            Console.WriteLine("Finished. Press any key to exit...");
            Console.ReadKey();
        }
    }
}

Notes:

  • Task.Run schedules the delegate on the thread pool.
  • await Task.Run(...) asynchronously waits for completion.
  • Task.Delay(100) is preferred over Thread.Sleep(100) in async code because it does not block the thread.
  • Removed the invalid Console.DisableEndOfProcess() – there is no such API in System.Console.

3. When to use Task.Run

Use Task.Run mainly when:

  • You have CPU-bound work that must not run on the UI thread.
  • You are in a console or desktop app and want to keep the UI responsive.

Do not wrap already-async I/O calls (like HttpClient.GetAsync) in Task.Run; just await them directly (see CSharp-AsyncAwait-Basics.md).


4. Next steps

  • Explore exception handling in async code together with CSharp-Exceptions-TryCatch.md.
  • Use tasks and async methods in MVVM commands (CommunityToolkit.MVVM.md).
  • Read the official task-based async programming guide linked above for advanced patterns (cancellation, progress, etc.).

Clone this wiki locally