Q: multi-threading slower than single thread? Most of the application runtime is in this function:
function Panorama(var Solutions: TSolutionDynArray): Integer;
var
  I, J: Integer;
begin
  Result := 0;
  for I := Low(Solutions) to High(Solutions) do
    with Solutions[I] do begin
      Panorama := Level;
      for J := Low(FPertinentPanoramas[I, Level])
          to High(FPertinentPanoramas[I, Level]) do
        if Level > Solutions[FPertinentPanoramas[I, Level, J]].Level then
          Panorama := Panorama + 1
        else
          Panorama := Panorama - 1;
      Result := Result + Panorama;
    end;
end;

where
  TSolution = record
    Level, Panorama: Integer;
  end;
  TSolutionDynArray = array of TSolution;

FPertinentPanoramas is a multidimensional array of Integers (initialized once and then remains constant)
Computation of I, J is not dependent on any other I, J -- this problem can therefore be easily parallelized: simply add parameters LowSolutions and HighSolutions and modify the loop to
for I := LowSolutions to HighSolutions do

E.g.: instead of 1..1000, multithread 1..250, 251..500, 501..750, 751..1000
However, for whatever reason, single thread is always faster than multithreading (threads are created once and reused -- ExecuteAnonymousThreads; Event.WaitFor;):
type
  TAnonymousThread = class(TThread)
  private
    FEvent: TEvent;
    FProc: TProc;
  protected
    procedure Execute; override;
    procedure SetProc(const Proc: TProc);
  public
    constructor Create(const Proc: TProc = nil);
    property Proc: TProc write SetProc;
  end;

var
  AnonymousThreads: array of TAnonymousThread;
  Event: TEvent;

procedure InitializeThreads(const N: Integer);
procedure ExecuteAnonymousThreads;

implementation

var
  FCriticalSection: TCriticalSection;
  FCounter: Integer;

procedure Counter;
begin
  with FCriticalSection do begin
    Acquire;
    FCounter := FCounter - 1;
    if FCounter = 0 then
      Event.SetEvent;
    Release;
  end;
end;

constructor TAnonymousThread.Create(const Proc: TProc = nil);
begin
  inherited Create;
  FreeOnTerminate := True;
  FEvent := TEvent.Create;
  SetProc(Proc);
end;

procedure TAnonymousThread.Execute;
begin
  while not Terminated do begin
    FEvent.WaitFor;
    FEvent.ResetEvent;
    if Assigned(FProc) then
      FProc;
    Counter;
  end;
end;

procedure TAnonymousThread.SetProc(const Proc: TProc);
begin
  FProc := Proc;
end;

procedure InitializeThreads(const N: Integer);
var
  I: Integer;
begin
  Event := TEvent.Create;
  FCriticalSection := TCriticalSection.Create;
  SetLength(AnonymousThreads, N);
  for I := Low(AnonymousThreads) to High(AnonymousThreads) do
    AnonymousThreads[I] := TAnonymousThread.Create;
end;

procedure ExecuteAnonymousThreads;
var
  I: Integer;
begin
  FCounter := Length(AnonymousThreads);
  Event.ResetEvent;
  for I := Low(AnonymousThreads) to High(AnonymousThreads) do
    AnonymousThreads[I].FEvent.SetEvent;
end;


The obvious question is why is multithreaded performance so inferior, and is there something that can be done to improve this?
EDIT:

*

*I have previously attempted to use non-anonymous threads with Execute hardcoded to the function, but there were no noticeable improvements, so I have posted the simpler anonymous code

*While TParallel.For performs horribly within the function loop, I have now had encouraging results using it on the function:

  TParallel.For(Low(A), High(A),
    procedure(I: Integer)
    begin
      Panorama(SolutionsPool[I]);
    end);


A: In general, I will answer the question: why does one thread work faster than if it is divided into several.
The processor performs one task at a time, it cannot do two tasks at a time. Windows too, but it simulates multithreading. It seems to us that the programs work at the same time, in fact they work in turn.
Your threads are not running at the same time, but in turn. Conditional: Each thread in turn executes one command.
You just split the stream into several and added synchronization between them (I didn't go into details in your code, it doesn't make sense for this). No matter how hard you try, your code will be executed at least at the same speed (highly doubtful). Faster - never. If you can do it faster, then it can be implemented in one thread (it will be even faster). If I were you, I would try to make as few threads and synchronization between them as possible.
In the new books, I have not seen a description of the operation of the computer, in the old books it is described.
Assembly language for Intel processors Kip.R.Irwin //Page 71
