Skip to content

Latest commit

 

History

History
117 lines (77 loc) · 2.01 KB

01-thread-vs-task.md

File metadata and controls

117 lines (77 loc) · 2.01 KB

01 - Thread vs Task

Goal

Understand the difference between:

  • sequential execution
  • raw Thread
  • Task
  • Task.WhenAll

Step 1: Inspect the interface

public interface IActionRunner
{
    Task RunAsync(
        IReadOnlyCollection<Func<CancellationToken, Task>> actions,
        CancellationToken cancellationToken);
}

Step 2: Implement sequential execution

Open:

src/MultithreadingLab.Core/ActionRunners/SequentialActionRunner.cs

This version should execute one action after another.

Step 3: Implement raw Thread execution

Open:

src/MultithreadingLab.Core/ActionRunners/ThreadActionRunner.cs

Requirements:

  • Create one Thread per action.
  • Start each thread.
  • Join each thread.
  • Capture exceptions.
  • Throw an AggregateException if any action fails.

Step 4: Implement Task-based execution

Open:

src/MultithreadingLab.Core/ActionRunners/TaskActionRunner.cs

Requirements:

  • Schedule actions using Task.Run.
  • Await all using Task.WhenAll.
  • Respect cancellation.
  • Do not swallow exceptions.

Step 5: Add tests

Create tests for:

  • empty input
  • all actions executed
  • exception propagation
  • cancellation behavior

Step 6: Benchmark

Run:

dotnet run -c Release --project benchmarks/MultithreadingLab.Benchmarks --filter *ActionRunner*

Compare:

  • sequential
  • raw thread
  • task-based

Trade-offs

Raw Thread

Pros:

  • Full control over thread lifetime.
  • Good for understanding low-level behavior.

Cons:

  • Expensive to create.
  • Poor scalability when creating many threads.
  • Easy to misuse with async code.

Task

Pros:

  • Better default abstraction.
  • Uses ThreadPool for CPU-bound work.
  • Composes naturally with async/await.

Cons:

  • Can still cause ThreadPool starvation if abused.
  • Task.Run should not be used blindly around already-async I/O operations.

Key takeaway

Use raw Thread for learning or special low-level scenarios. Use Task, async/await, and higher-level primitives for most application code.