1. Home
  2. Task.Run vs. TaskFactory.StartNew

Task.Run vs. TaskFactory.StartNew

Task.Run vs. TaskFactory.StartNew

Task.Run vs. TaskFactory.StartNew

๐Ÿงต Task.Run vs. TaskFactory.StartNew in C#

When working with asynchronous or parallel code in C#, you'll inevitably encounter two common ways to start tasks: Task.Run and TaskFactory.StartNew. At first glance, they seem similar โ€“ but they behave differently and should be used appropriately depending on the context.

In this article, you'll learn:

  • What the difference is between Task.Run and TaskFactory.StartNew
  • Which one you should prefer
  • Code examples for both approaches

โœ… Task.Run

Task.Run was introduced in .NET 4.5 to simplify asynchronous programming. It wraps the more complex TaskFactory.StartNew with sensible defaults and is ideal for offloading CPU-bound work.

Example

public Task RunWithTaskRunAsync()
{
    return Task.Run(() =>
    {
        // Simulated background work
        Thread.Sleep(1000);
        Console.WriteLine("Executed with Task.Run");
    });
}

Key Characteristics

  • Uses TaskScheduler.Default (ThreadPool)
  • Ideal for CPU-bound operations
  • Automatically flows the current execution context (e.g., HttpContext, SecurityContext)
  • Simple to use

โš™๏ธ TaskFactory.StartNew

TaskFactory.StartNew offers full control over task creation. You can configure schedulers, creation and continuation options โ€“ at the cost of increased complexity.

Simple Example

public Task RunWithTaskFactoryAsync()
{
    TaskFactory factory = new TaskFactory();

    return factory.StartNew(() =>
    {
        Thread.Sleep(1000);
        Console.WriteLine("Executed with TaskFactory.StartNew");
    });
}

With Configuration Options

public Task RunWithTaskFactoryOptionsAsync()
{
    TaskFactory factory = new TaskFactory(
        CancellationToken.None,
        TaskCreationOptions.DenyChildAttach,
        TaskContinuationOptions.None,
        TaskScheduler.Default);

    return factory.StartNew(() =>
    {
        Thread.Sleep(1000);
        Console.WriteLine("Executed with TaskFactory and options");
    });
}

๐Ÿ†š Comparison Table

FeatureTask.RunTaskFactory.StartNew
Introduced In.NET 4.5.NET 4.0
Ease of Useโœ… Simpleโš ๏ธ Complex
Context Flowingโœ… YesโŒ No (must be configured manually)
Custom Scheduler SupportโŒ Noโœ… Yes
Async Lambda Friendlyโœ… YesโŒ No (requires care)
Configurable OptionsโŒ Noโœ… Yes

๐ŸŸข Recommendation

  • โœ… Use Task.Run for offloading simple CPU-bound tasks in async code.
  • โŒ Avoid TaskFactory.StartNew unless you need custom configuration, scheduling, or advanced scenarios.
  • โš ๏ธ Do not use TaskFactory.StartNew with async lambdas, unless you're explicitly handling the returned Task โ€“ it does not unwrap the async method properly.

Conclusion

In modern .NET applications, Task.Run is almost always the safer and cleaner choice. It supports async/await, ensures proper context handling, and simplifies code.