FreePascal // Multithread ?

Pascal, Basic und andere nicht aufgelistete
nufan
Wiki-Moderator
Beiträge: 2558
Registriert: Sa Jul 05, 2008 3:21 pm

Re: FreePascal // Multithread ?

Beitrag von nufan » So Feb 06, 2022 8:53 pm

osculumobscenum hat geschrieben:
So Feb 06, 2022 8:21 pm
Möglicherweise werde ich meine sehr spärlichen C-Kenntnisse aufpolieren und mir diese OpenMP-Sache mal zu Gemüte führen, und sei es nur für Benchmark-Zwecke.
Ich behaupte zu C und OpenMP können wir dir bessere Unterstützung anbieten als zu Pascal :)

osculumobscenum
Beiträge: 27
Registriert: Do Okt 31, 2013 9:03 pm

Re: FreePascal // Multithread ?

Beitrag von osculumobscenum » Mo Feb 07, 2022 10:11 am

Das werde ich zu gegebener Zeit dann dankend annehmen! :-)

osculumobscenum
Beiträge: 27
Registriert: Do Okt 31, 2013 9:03 pm

Re: FreePascal // Multithread ?

Beitrag von osculumobscenum » Mo Feb 07, 2022 10:32 pm

Ich werde wohl mangels genügend Zeit auf weitere Recherchen verzichten müssen, aber der Komplettheit halber will ich noch folgendes festhalten :

Ich habe folgenden Code in Freepascal angesetzt, der EINEN Prozessorkern nutzt :

Code: Alles auswählen

program grosse_primzahlen;
uses crt;
var
  i, j, start, ende, jstop : qword;
  prim : boolean;

begin
  clrscr;
  writeln;
  writeln('Berechnung grosser Primzahlen');
  writeln('-----------------------------');
  write('starten bei : ');readln(start);
  write('enden bei   : ');readln(ende);

  i:=start;
    repeat
      prim:=true;
      inc(i);
      j:=1;
      jstop:=round(sqrt(i));
      repeat
        inc(j);
        if i mod j = 0 then prim := false;
      until j>= jstop;

      if prim=true then writeln(i,' ist Primzahl');

      until i= ende;
end.


...und folgenden Code in C zusammen-gepfuscht, der mithilfe dieser OpenMP-Lösung alle Prozessorkerne nutzt :

Code: Alles auswählen

//  Über die Unit OpenMP kann die Nutzung aller Kerne bei aufwändigen Rechnereien erreicht werden.

#include <omp.h>
#include <stdio.h>
#include <math.h>

int check_prime(int);

int main()
{
   unsigned int n, result; // 0 to 4294967295
#pragma omp parallel for
   for (n=1000000;n<=1500000; n++)
   {
    result = check_prime(n);

   if (result == 1)
      printf("%d is prime.\n", n);
   }

   return 0;
}

int check_prime(int a)
{
   unsigned int c, ptrue;
   unsigned int h = (int)sqrt(a);
   ptrue=1;
 //  printf("%d als Wurzel \n", h);
   for (c = 2; c <= h; c++)
   {
      if (a%c == 0) ptrue = 0;
   }
   if (ptrue == 0)
      return 0;
   if (ptrue == 1)
	  return 1;
}
Bei beiden wird jeweils durch Teilung der zu untersuchenden Werte bis Wurzel(Wert) mit der Modulo-Division ein Rest gesucht, also das gleiche Verfahren genutzt.

Bei einer Untersuchung eines Wertebereichs zwischen 1.000.000 und 1.500.000 hat sich das Einkern-Pascal-Programm mit 4,5 Sekunden geschlagen, während das Mehrkern-C-Programm wirklich nur eine halbe Sekunde gebraucht hat. (Ich habe dabei die Schreibausgabe in eine Datei umgeleitet, weil Schreiben an der Konsole zu lange dauert und das Ergebnis verfälscht.)
Aber man sieht definitiv, die OpenMP-Einbindung macht das ganze schon viel schneller, auch wenn die Sortierung der Primzahlen dann nicht mehr stimmt. ;-)

Benutzeravatar
dmac
Beiträge: 1
Registriert: Sa Mär 01, 2025 1:14 pm

Re: FreePascal // Multithread ?

Beitrag von dmac » Sa Mär 01, 2025 2:40 pm

Dass die C Variante hier schneller ist, ist nicht verwunderlich. Der FreePascal Compiler ist nicht gerade dafür bekannt gut zu optimieren, schon garnicht im Vergleich zu den "Großen" wie gcc oder clang. Seit dem GCC 13 kann man das sogar ein bisschen vergleichen, denn da gibt es ein Modula-2 Frontend. Und Pascal in Modula-2 zu transformieren ist ziemlich einfach. Man kann dann auch schön im Compiler Explorer die Unterschiede sehen. Zum Beispiel sieht man, dass der GCC SIMD Maschinencode (also MMX/SSE/AVX) generiert.

Dadurch dass die äußere Schleife kein Abhängigkeit hat, kann man jeden Test einer spezifischen Zahl als ein Thread realisieren. Wenn man also von 10 bis 100 testet, sind das 90 Threads, wobei in jedem Thread die innere Schleife läuft. Das ist keine gute Idee, weil das Spawnen eines Threads und dann die Verwaltung aller Threads vermutlich mehr Zeit kostet als die Abarbeitung der inneren Schleife. Insbesondere muss die Ausgabe der Primzahl gegen parallele Zugriffe geschützt werden (Stichwort Mutex). Idealerweise verwendet man einen Threadpool mit so vielen Threads, wie man CPU-Kerne hat, und dann "füttert" man die Threads bis alle Tests durchgelaufen sind. Die Primzahl gibt man auch nicht im Thread aus, sondern sammelt sie in einer Liste oder Queue. Idealerweise sollten diese "lock-free" sein oder gegen parallele Zugriffe geschützt werden. Das ist eigentlich eine sehr schöne Aufgabe für modernes C++.

Antworten