Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

C# Dictionary

  1. Home
  2. C# Dictionary
  3. Task.Run() / Task.Delay()

Task.Run() / Task.Delay()

Since: C# 5.0(2012)

Static methods for running tasks in the background or waiting asynchronously for a specified duration. This page also covers WhenAll() and WhenAny() for running multiple tasks in parallel.

Syntax

using System.Threading.Tasks;

// Runs a delegate on a background thread.
Task task = Task.Run(() => action);
Task<T> task = Task.Run(() => functionWithReturnValue);

// Waits asynchronously for the specified number of milliseconds.
await Task.Delay(milliseconds);

// Waits until all tasks complete.
await Task.WhenAll(task1, task2, task3);

// Waits until the first task completes.
Task first = await Task.WhenAny(task1, task2, task3);

Method List

MethodDescription
Task.Run(action)Executes a delegate on the thread pool and returns a Task representing its completion.
Task.Delay(ms)Returns a Task that completes after the specified number of milliseconds. Does not block the thread.
Task.WhenAll(tasks)Waits asynchronously until all tasks complete.
Task.WhenAny(tasks)Returns the first task to complete. Convenient for implementing timeouts.
Task.CompletedTaskReturns an already-completed Task. Used as a return value for synchronously completing code.
task.Wait()Blocks the current thread until the task completes.
task.ResultSynchronously retrieves the result of the task (waits until complete).

Sample Code

Program.cs
using System;
using System.Threading.Tasks;

// Runs a background computation with Task.Run.
Task<int> bgTask = Task.Run(() =>
{
    int sum = 0;
    for (int i = 1; i <= 100; i++) sum += i;
    return sum;
});
Console.WriteLine(await bgTask); // 5050

// Waits asynchronously with Task.Delay (async version of Thread.Sleep).
Console.WriteLine("Start");
await Task.Delay(1000); // Waits 1 second.
Console.WriteLine("1 second later");

// WhenAll: runs multiple tasks in parallel and waits for all to complete.
Task<string> t1 = Task.Run(async () => { await Task.Delay(100); return "Task 1"; });
Task<string> t2 = Task.Run(async () => { await Task.Delay(200); return "Task 2"; });
Task<string> t3 = Task.Run(async () => { await Task.Delay(50);  return "Task 3"; });

string[] results = await Task.WhenAll(t1, t2, t3);
Console.WriteLine(string.Join(", ", results)); // Task 1, Task 2, Task 3

// WhenAny: gets the first completed task (timeout example).
Task<int> longTask = Task.Run(async () => { await Task.Delay(5000); return 42; });
Task timeoutTask = Task.Delay(1000);

Task finished = await Task.WhenAny(longTask, timeoutTask);
if (finished == timeoutTask)
    Console.WriteLine("Timeout");
else
    Console.WriteLine($"Done: {longTask.Result}");

This produces the following output:

dotnet script task_run_delay.csx
5050
Start
1 second later
Task 1, Task 2, Task 3
Timeout

Practical Pattern: Parallel Fetch and Aggregation

A pattern for fetching multiple pieces of data in parallel and aggregating the results. Significantly faster than sequential awaits.

ParallelFetch.cs
using System;
using System.Diagnostics;
using System.Threading.Tasks;

// Async method that fetches a score (in practice, queries a DB or API).
static async Task<int> FetchScoreAsync(string name, int delayMs)
{
    await Task.Delay(delayMs);
    return name.Length * 100 + delayMs / 10;
}

var sw = Stopwatch.StartNew();

// Sequential execution: takes about 1500ms total.
sw.Restart();
int s1 = await FetchScoreAsync("Shinji Ikari", 500);
int s2 = await FetchScoreAsync("Rei Ayanami", 500);
int s3 = await FetchScoreAsync("Asuka Langley", 500);
Console.WriteLine($"Sequential: {s1 + s2 + s3} pts / {sw.ElapsedMilliseconds}ms");

// Parallel execution: completes in about 500ms (the longest task).
sw.Restart();
Task<int> p1 = FetchScoreAsync("Shinji Ikari", 500);
Task<int> p2 = FetchScoreAsync("Rei Ayanami", 500);
Task<int> p3 = FetchScoreAsync("Asuka Langley", 500);
int[] parallelResults = await Task.WhenAll(p1, p2, p3);
int total = parallelResults[0] + parallelResults[1] + parallelResults[2];
Console.WriteLine($"Parallel: {total} pts / {sw.ElapsedMilliseconds}ms");

This produces the following output:

dotnet script parallel_fetch.csx
Sequential: 3770 pts / 1510ms
Parallel: 3770 pts / 512ms

Practical Pattern: Implementing a Timeout with WhenAny

A pattern for implementing timeout handling by combining WhenAny with Task.Delay. Useful when CancellationToken is not available.

TaskTimeout.cs
using System;
using System.Threading;
using System.Threading.Tasks;

// Runs an async operation with a timeout.
static async Task<T?> WithTimeoutAsync<T>(Task<T> task, int timeoutMs)
{
    Task timeoutTask = Task.Delay(timeoutMs);
    Task finished = await Task.WhenAny(task, timeoutTask);

    if (finished == timeoutTask)
    {
        Console.WriteLine($"Timeout ({timeoutMs}ms)");
        return default;
    }
    return await task;
}

// Fast task (200ms)
Task<string> fastTask = Task.Run(async () =>
{
    await Task.Delay(200);
    return "Kaworu Nagisa";
});

// Slow task (2000ms)
Task<string> slowTask = Task.Run(async () =>
{
    await Task.Delay(2000);
    return "slow data";
});

string? fastResult = await WithTimeoutAsync(fastTask, 500);
Console.WriteLine($"Fast task: {fastResult ?? "null"}");

string? slowResult = await WithTimeoutAsync(slowTask, 500);
Console.WriteLine($"Slow task: {slowResult ?? "null"}");

This produces the following output:

dotnet script task_timeout.csx
Fast task: Kaworu Nagisa
Timeout (500ms)
Slow task: null

Common Mistakes

Common Mistake 1: Deadlock from task.Result / task.Wait()

Using task.Result or task.Wait() inside an async method can cause a deadlock. This is especially dangerous in environments with ASP.NET or UI thread context.

using System;
using System.Threading.Tasks;

static async Task<int> GetDataAsync()
{
    await Task.Delay(100);
    return 42;
}

// NG: .Result inside an async method risks deadlock.
async Task Main()
{
    int result = GetDataAsync().Result; // Deadlock risk.
    Console.WriteLine(result);
}

The corrected version looks like this:

using System;
using System.Threading.Tasks;

static async Task<int> GetDataAsync()
{
    await Task.Delay(100);
    return 42;
}

// OK: Always use await.
async Task Main()
{
    int result = await GetDataAsync();
    Console.WriteLine(result); // 42
}

Common Mistake 2: Only the First Exception Is Caught from WhenAll

When multiple tasks in WhenAll fail, awaiting it catches only the first exception. Inspect task.Exception to see all exceptions.

using System;
using System.Threading.Tasks;

Task<int> fail1 = Task.Run<int>(() => throw new Exception("Error 1"));
Task<int> fail2 = Task.Run<int>(() => throw new Exception("Error 2"));
Task<int[]> whenAll = Task.WhenAll(fail1, fail2);

try
{
    await whenAll;
}
catch (Exception ex)
{
    // Only the first exception is caught by await.
    Console.WriteLine($"catch: {ex.Message}");

    // Inspect InnerExceptions to see all exceptions.
    if (whenAll.Exception != null)
    {
        foreach (Exception inner in whenAll.Exception.InnerExceptions)
            Console.WriteLine($"  Inner: {inner.Message}");
    }
}

This produces the following output:

dotnet run
catch: Error 1
  Inner: Error 1
  Inner: Error 2

Overview

Task.WhenAll() runs multiple async operations in parallel and waits for all of them to complete. This is faster than chaining sequential awaits because the total wait time is the duration of the longest task.

Using task.Result or task.Wait() inside an async method can cause a deadlock. Always use await inside async code. For async/await basics, see async / await. For cancellation, see CancellationToken.

If you find any errors or copyright issues, please .