Recently, I wrote some new demo for Delphi PPL (Parallel Programming Library), while doing some research for an online class -- which is available since last week on the Embarcadero Academy site ("Anonymous Methods in Delphi"), along with a new overall bundle of my classes ("Master Modern Delphi Language Techniques").

In the past I've used different ways to explain tasks and compare them to threads. Tasks are lightweight and managed more efficiently, than threads. The PPL creates a thread pool and assigns pending tasks (and their code) to a pool of threads that depends on your CPU cores and current workload. But these descriptions might still explain tasks and threads as fairly similar in scope. Now let's look at this source code snippet:

      procedure TForm12.btn100sClick(Sender: TObject);
var
  tasks: array of ITask;
  Value: Integer;
  I: Integer;
begin
  SetLength(tasks, 100000);
  Value := 0;

  for I := Low (tasks) to High (tasks) do
      begin
    tasks[I] := TTask.Create (procedure ()
    begin
      TInterlocked.Increment (Value);
    end);
    tasks[I].Start;
  end;

  TTask.WaitForAll (tasks);
  Memo1.Lines.Add(Value.ToString);
end;

As you can see this event handler creates not hundred, but hundred thousand tasks. Each of them has an extremely simple operation to complete -- fairly nonsensical, I know. But you can create 100,000 tasks and they'll all done done in less than a second, on my computer. Consider creating 100,000 threads! that would create a significant extra overhead. By running this code, the tasks are assigned to a few threads in a pool, as you can see in the debugger:

Small demo and pretty much useless code, but I think it does a good job in highlighting the lightweight and flexible nature of nature of tasks, when compared to threads.