![]() |
grundsätzliche Frage zu Multithreading
Hi
Die Tage habe ich die Geschwindigkeit von C#, Delphi und C++ getestet. Dazu habe ich in einer 10-Mio.-For-Schleife einen Vektor normalisiert. Dabei kam heraus, dass C# dafür 1,5 Sekunden benötigt. Delphi 0,5 Sekunden und C++ irgendwas um 0,003 Sekunden. Dass C# am langsamsten ist, dachte ich mir fast. Aber der Unterschied zwischen Delphi und C++ ist arg groß. Da ich nun für meine KI jeden Leistungsvorteil nutzen möchte, will ich sämtliche Berechnungen über C++ erledigen, wobei die Verwaltung der KI selbst in Delphi erfolgt. (Ich mag halt Delphi und will C++ nur dann nutzen, wenn es unbedingt nötig ist) Der Aufbau sieht so aus: Hauptprogramm(3D-Engine) --> KI(Delphi-DLL) --> reine Berechnungen(C++-DLL) Was mich nun interessieren würde ist, inwieweit sich das mit Multithreading vereinbaren lässt. In der Delphi-DLL werden, z.B. bei einem Quad-Core, 4 Threads erstellt, die ständig auf exportierte Funktionen der C++-DLL zugreifen (Pathfinding, Fuzzy-Logic, usw.). Geht das so überhaupt? Danke |
AW: grundsätzliche Frage zu Multithreading
Ich sehe jetzt nicht ganz, eine weitere "Zwischen-DLL" überhaupt nötig ist, aber noch eher glaube ich, dass man den generellen Performance-Unterschied jetzt nicht an einer Vektor-Operation festmachen sollte. Ich glaube nicht, dass es so einen argen Unterschied gibt... :oops:
|
AW: grundsätzliche Frage zu Multithreading
Eine weitere Idee um es ggf. in Delphi noch schneller zu kriegen:
1. inline funktion 2. inline assembler (ggf. sogar mit MMX, SSE ?) Dann sparst du dir den ganzen C++ Kram. |
AW: grundsätzliche Frage zu Multithreading
Und wenn man wirklich das letzte Bischen herausquetschen will, wäre
![]() ![]() |
AW: grundsätzliche Frage zu Multithreading
@Günther
Wie gesagt, die reine Verwaltung mache ich lieber in Delphi. Nur den Mathe-Kram würde ich gerne wegen der Geschwindigkeit auslagern. @General Inline Assembler kann ich nicht nutzen, da der 64bit-Delphi-Compiler sowas nicht kann. (Delphi XE3) |
AW: grundsätzliche Frage zu Multithreading
@Medium:
Mit CUDA binde ich mich leider an nVidia. Für ein Spiel ist das nicht sinnvoll. OpenCL hingegen klingt ganz gut. |
AW: grundsätzliche Frage zu Multithreading
@Gargamel: Soweit ich weiß kannst du zwar keine kompletten inline-Funktionen mit asm - end machen aber du kannst glaube ich sowas machen:
Delphi-Quellcode:
? Kann mich aber auch täuschen.
begin
asm end; end; Ansonsten probier mal deine Funktion zum normalisieren von Vektoren mit inline; zu markieren. Ich denke das sollte wie gesagt auch noch mal etwas bringen. |
AW: grundsätzliche Frage zu Multithreading
Es wäre sowieso kein gültiger Vergleich, wenn beide Algorithmen nicht zu 100% identisch ablaufen. Dh. wenn in C++ geinlinet wird, dann muss in Delphi das auch geschehen und vice versa. Von daher ist es eig. relativ egal.
Ich würde übrigens gerne Code sehen... |
AW: grundsätzliche Frage zu Multithreading
Das gehört hier wahrscheinlich nicht mehr hin.
Aber gibt es überhaupt Nvidia-Karten mit OpenCL? Ich dachte die bleiben weiterhin bei CUDA. Auch haben Sie das Format geöffnet, vielleicht springt ja sogar ATI auf diesen Zug auf... |
AW: grundsätzliche Frage zu Multithreading
Ein Unterschied von 2-5% zwischen den einzelnen Compilern ist durchaus denkbar, deine Ergebnisse mit hundertfacher Laufzeit deuten aber eher auf Fehler in der Implementierung hin.
Assembler ist wirklich nur das letzte Mittel, wenn alle anderen Optimierungen schon durch sind. OpenCL scheint hier der bessere Weg zu sein. Multithreading und DLL-Aufrufe geht natürlich, sofern die Funktionen in der DLL auch threadsicher implementiert sind oder nur von einem Thread verwendet werden. |
AW: grundsätzliche Frage zu Multithreading
Zitat:
Delphi-Quellcode:
__declspec(dllexport) int calcCPP(void)
{ int sum = 0; for (int i = 0; i < (100000000 - 1); i++) { float vecX = 5.7458F; float vecY = 3.758F; float vecZ = 7.12544F; float len = sqrt(vecX*vecX+vecY*vecY+vecZ*vecZ); float normX = vecX / len; float normY = vecY / len; float normZ = vecZ / len; sum+=1; } return sum; } |
AW: grundsätzliche Frage zu Multithreading
Und in Delphi?
|
AW: grundsätzliche Frage zu Multithreading
Delphi-Quellcode:
procedure calcDelphi();
var vecX, vecY, vecZ, len, normX, normY, normZ:single; i:integer; Begin for i:=0 to 100000000 - 1 do Begin vecX:= 5.7458; vecY:= 3.758; vecZ:= 7.12544; len:=Sqrt(vecX*vecX+vecY*vecY+vecZ*vecZ); normX:= vecX / len; normY:= vecY / len; normZ:= vecZ / len; End; End; procedure calcDelphi_withCPP(); Begin calcCPP(); // importierte Funktion End; |
AW: grundsätzliche Frage zu Multithreading
Wobei ich bei solchen Implementierungen immer vorsichtig wäre, denn hier könnte der Compiler auch einfach die Berechnungen wegoptimieren, denn die Ergebnisse sind rein lokal ;)
Und gleich implementiert sind die auch nicht |
AW: grundsätzliche Frage zu Multithreading
Mach doch am besten mal eine Funktion mit der du allgemein einen Vektor normalisierst.
Und die rufst du dann 1000000x auf oder so. Macht das einen Unterschied? Kann mir kaum vorstellen dass C++ da so viel schneller sein kann. |
AW: grundsätzliche Frage zu Multithreading
@General:
Habe ich schon gemacht. In CPP wurde nur die reine Funktion implementiert und in Delphi x-mal aufgerufen. Das Ergebnis war, dass die benötigte Zeit in Delphi von 0,5 Sekunden auf 0,2 Sekunden sank. |
AW: grundsätzliche Frage zu Multithreading
@Sir Rufo: Ich hatte einen ähnlichen Gedanken. Möglicherweise erkennt der CPP-Compiler, dass in der Funktion eh immer die gleichen Werte berechnet werden und ruft die Funktion halt nur 1x auf, statt die ganze Schleife komplett durchzulaufen.
|
AW: grundsätzliche Frage zu Multithreading
Ich meinte eher dass du sowohl in C++ als auch in Delphi den Code so umänderst dass du jeweils eine
normalisiereVektor-Funktion hast. Quasi unter realen Bedingungen^^
Delphi-Quellcode:
Das gleiche dann nochmal in C++ und dann nochmal die Geschwindigkeit messen.
type
TVector = record x,y,z: Single; end; function normalisieren(AVector: TVector): TVector; // inline; var len: Integer; begin len := sqrt(AVector.x*AVector.x+AVector.y*AVector.y+AVector.z*AVector.z); Result.x := AVector.x / len; Result.y := AVector.y / len; Result.z := AVector.z / len; end; procedure Testen; var i: Integer; vec: TVector; begin for i:=0 to 100000000 - 1 do begin vec.x := 5.7458; vec.y := 3.758; vec.z := 7.12544; vec := normalisieren(vec); end; end; |
AW: grundsätzliche Frage zu Multithreading
Also bei 10 Mio habe ich ja schon gestutzt. Aber 100 Mio. Berechnungen in 0,003 Sekunden ... no way!
Bei einem 3GHz Rechner sind das 11 Berechnungen (Schleifendurchläufe) pro Takt. Da das ganze nicht irgendwie parallelisiert ist, kann das nicht sein! Du hast da irgendwo einen Fehler im Vergleich drin, die genannte Optimierung wird sicherlich durchgeführt. Der Vollständigkeit halber wäre ich auch noch an deinem C# Quellcode interessiert :stupid: |
AW: grundsätzliche Frage zu Multithreading
@General: Gerade probiert. Jetzt braucht Delphi 1,9 Sekunden.
|
AW: grundsätzliche Frage zu Multithreading
Und in C++ ? (darum gings ja in erster Linie :D)
Und dann noch den C# Code! :mrgreen: |
AW: grundsätzliche Frage zu Multithreading
@jfheins: Gerne doch.
Delphi-Quellcode:
void calcCSharp()
{ for (int i = 0; i < (100000000 - 1); i++) { float vecX = 5.7458F; float vecY = 3.758F; float vecZ = 7.12544F; float len = Mathf.Sqrt(vecX*vecX+vecY*vecY+vecZ*vecZ); float normX = vecX / len; float normY = vecY / len; float normZ = vecZ / len; } } |
AW: grundsätzliche Frage zu Multithreading
@Gargamel
Implementiere doch mal in allen 3 Sprachen die Funktion
Delphi-Quellcode:
exact gleich und führe dann deine Messung erneut durch. Diese Werte wären interessant im Vergleich zu sehen
type
TVector = record x,y,z: Single; end; function normalisieren(AVector: TVector): TVector; // inline; var len: Integer; begin len := sqrt(AVector.x*AVector.x+AVector.y*AVector.y+AVector.z*AVector.z); Result.x := AVector.x / len; Result.y := AVector.y / len; Result.z := AVector.z / len; end; |
AW: grundsätzliche Frage zu Multithreading
Mit dem nachfolgenden C++-Code sind es 0,8 Sekunden.
Delphi-Quellcode:
TVector normalisieren(TVector AVector)
{ float len = sqrt(AVector.x*AVector.x+AVector.y*AVector.y+AVector.z*AVector.z); AVector.x = AVector.x / len; AVector.y = AVector.y / len; AVector.z = AVector.z / len; return AVector; } __declspec(dllexport) void cppTesten() { TVector vec; for (int i=0; i< 100000000 - 1; i++) { vec.x = 5.7458F; vec.y = 3.758F; vec.z = 7.12544F; vec = normalisieren(vec); } } |
AW: grundsätzliche Frage zu Multithreading
@alle: Damit jetzt alle drei Sprachen abgedeckt wurden, hier noch der C#-Code. Die benötigte Zeit hierfür beträgt 2,9 Sekunden.
Delphi-Quellcode:
public struct TVector
{ public float x; public float y; public float z; } //////////////////////////// public TVector normalisieren(TVector AVector) { float len = Mathf.Sqrt(AVector.x * AVector.x + AVector.y * AVector.y + AVector.z * AVector.z); AVector.x = AVector.x / len; AVector.y = AVector.y / len; AVector.z = AVector.z / len; return AVector; } void calcCSharp_V2() { TVector vec; for (int i = 0; i < 100000000 - 1; i++) { vec.x = 5.7458F; vec.y = 3.758F; vec.z = 7.12544F; vec = normalisieren(vec); } } |
AW: grundsätzliche Frage zu Multithreading
Also ernsthaft.. Jetzt würde ich noch gerne den Maschinencode der normalisieren Funktion in Delphi und C++ sehen :mrgreen:
Wo spart C++ denn da über die Hälfte der Zeit? |
AW: grundsätzliche Frage zu Multithreading
Zitat:
Zitat:
Schlägt da ein Vektorisierer zu, wie bei Microsoft oder Intel ? ![]() |
AW: grundsätzliche Frage zu Multithreading
1. Für C++ habe ich Visual C++ 2010 Express verwendet. Ahnung habe ich aber nicht, welche Optimierungen da vorgenommen werden.
2. Thema Multithreading: Nehmen wir an, es ist ein QuadCore, ich erstelle 4 Threads und es gibt 4 KI-Objekte. Jedes Objekt läuft auf einem separaten Kern. Jetzt wird, auch angenommen, ständig in jedem Objekt ein Vektor normalisiert. Die vier Threads laufen über Delphi, jedoch wird die "normalisieren"-Funktion aus einer C++-DLL aufgerufen. Würde das funktionieren oder gibt es da Probleme? |
AW: grundsätzliche Frage zu Multithreading
Letztens las ich erst, dass man für intensive Berechnungen 2*CPUKerne an Threads benutzen kann.
Die aufgerufenen Funktionen laufen immer in diesem Kontext (wenn man das nicht aktiv ändert und in einen weiteren Thread übergibt) |
AW: grundsätzliche Frage zu Multithreading
Jeder Thread hat doch seinen eigenen Stack, das Beispiel mit der Vektor-Normalisierung dürfte doch problemlos klappen?
|
AW: grundsätzliche Frage zu Multithreading
Zitat:
Aber wie schon gesagt, dass VC++ bei gleichen Code deutlich schneller ist als der Builder, ist völlig normal. Das ein gewisser Unterschied auch zu Delphi besteht, ist nicht ausgeschlossen. |
AW: grundsätzliche Frage zu Multithreading
Ich danke erstmal allen hier.
Vermutlich werde ich es so machen, dass ich alle Verwaltungsaufgaben der KI über Delphi erledige und komplexere Berechnungen C/C++ überlasse. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:10 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz