Leistung mit THREADS geringer ohne?

Für allgemeine Fragen zur Programmierung mit PureBasic.
ST4242
Beiträge: 42
Registriert: 29.10.2011 16:54

Leistung mit THREADS geringer ohne?

Beitrag von ST4242 »

Hallo, dies ist mein erster Beitrag in diesem Forum obwohl ich schon länger mit PUREBASIC programmiere.

Aktuell wollte ich einen Vorgang (Sortieren von großen Datenmengen) mit Threads beschleunigen (Intel I7 mit 4 echten Kernen).

Hierbei hat es gezeigt, das bei der zuschaltung weiterer Kerne der Prozess sogar länger dauert.

Nun habe ich mal ein kleines Testprogramm geschrieben um andere Fehler auszuschliessen aber auch hier zeigt das Bild.
Bei mir sind die Prozesse welche MT ablaufen bis zu 50% langsamer als ein singlecore Thread und das bei gleichem Kerntakt bei Single als MultiCore
Wie ist eure Meinung dazu?
Gruß Stefan

Code: Alles auswählen

; Testprogramm für die Leistungmessung bei Nutzung von Threads
Structure thMEM
  zaehler.i
  zaehler2.i
  zeitInMS.i
  thid.i
EndStructure
Procedure zaehlenbis(*m.thmem)
  Protected t
  t=ElapsedMilliseconds()
  Repeat
    *m\zaehler+1
    zaehler2+2
    zaehler2=zaehler*zaehler2
    zaehler2/2
    zaehler2=0
  Until ElapsedMilliseconds()-t>*m\zeitInMS
EndProcedure


Dim mem.thmem(30)
Define erg.s,used.i=2
mem(0)\zeitInMS=5000

zaehlenbis(@mem(0))
i=0
erg=erg+"Ergebniss Single = "+Str(mem(i)\zaehler)+Chr(10)+Chr(13)
mem(0)\zaehler=0
mem(0)\thid=CreateThread(@zaehlenbis(),@mem(0))
WaitThread(mem(0)\thid)
erg=erg+"Ergebniss sThread= "+Str(mem(i)\zaehler)+Chr(10)+Chr(13)

  For i=0 To used
    mem(i)\zeitInMS=mem(0)\zeitInMS
    mem(i)\zaehler=0
  Next i
  For i=0 To used
    mem(i)\thid=CreateThread(@zaehlenbis(),@mem(i))
  Next
  For i=0 To used
    If mem(i)\thid:WaitThread(mem(i)\thid):EndIf
  Next
  For i=0 To used
    erg=erg+"Ergebniss Nr. "+Str(i)+"   = "+Str(mem(i)\zaehler)+Chr(10)+Chr(13)
  Next i
  
  Define m1.thmem,m2.thmem,m3.thmem,m4.thmem
  m1\zeitInMS=mem(0)\zeitInMS
  m2\zeitInMS=mem(0)\zeitInMS
  m3\zeitInMS=mem(0)\zeitInMS
  m4\zeitInMS=mem(0)\zeitInMS
  m1\thid=CreateThread(@zaehlenbis(),@m1)
  m2\thid=CreateThread(@zaehlenbis(),@m2)
  m3\thid=CreateThread(@zaehlenbis(),@m3)
  m4\thid=CreateThread(@zaehlenbis(),@m4)
  WaitThread(m1\thid)
  WaitThread(m2\thid)
  WaitThread(m3\thid)
  WaitThread(m4\thid)
  erg=erg+"Ergebniss Nr. 1  X= "+Str(m1\zaehler)+Chr(10)+Chr(13)
  erg=erg+"Ergebniss Nr. 2  X= "+Str(m2\zaehler)+Chr(10)+Chr(13)
  erg=erg+"Ergebniss Nr. 3  X= "+Str(m3\zaehler)+Chr(10)+Chr(13)
  erg=erg+"Ergebniss Nr. 4  X= "+Str(m4\zaehler)+Chr(10)+Chr(13)
  
MessageRequester("Ergebnisse",erg)
  
 
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Leistung mit THREADS geringer ohne?

Beitrag von ts-soft »

Mehrere Threads führen nicht zwangsläufig zu mehr Geschwindigkeit!
Im Idealfalle erhält ein Thread, eine Aufgabe die kein Zugriff zu anderen sharedobjekten erfordert, die dieser alleine
zuende bringen kann und nur noch den Erfolg meldet.
Wenn es denn mehrere solcher Threads gibt, gibt es mit Sicherheit eine Beschleunigung des Programmes.
Aber abgesehen von diesem Idealfall wird es wohl eher darauf hinauslaufen, das Objekte geschützt werden und
der ganze Mutex-Kram mehr oder weniger, diesen Gewinn wieder auffrißt. Hierbei reicht es aber im allgm., wenn
der Main-Loop entlastet wird und das Programm stabil läuft. Das ist die Hauptaufgabe von Threads (Main-Loop entlasten).

Die Leistung kann dementsprechend auch durch Threads abnehmen. Hierbei sind es aber meist fehler durch falsche gesetzte
Mutexe.

Auch das ständige Neustarten eines Threads kann dauern, hier kann es effektiver sein, den Thread nacheinander mit Daten zu füttern,
ohne ihn zu beenden.

Zu dem Beispielcode: Schöner Code, ???

Gruß
Thomas
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
Imhotheb
Beiträge: 192
Registriert: 10.10.2014 13:14
Computerausstattung: Intel 8086, 640 KB RAM, Hercules Video Adapter, 2 x 5 1/4" 360kb Floppy, MS-DOS 3
Wohnort: Wolfenbüttel

Re: Leistung mit THREADS geringer ohne?

Beitrag von Imhotheb »

Threads benötigen etwas mehr "Verwaltungsarbeit". Diese verbraucht zusätzliche Ressourcen und erhöht dadurch die Gesamtauslastung und verbraucht CPU-Cyclen. Aber für rechenintensive Arbeiten, z. B. komprimieren von Daten oder wie bereits von TS-Soft erwähnt, das entlasten der Hauptschleife bzw. die Reaktion des Programms zu erhöhen, sind sie bestens geeignet.
weil einfach einfach einfach ist ... mach' ich es anders
ST4242
Beiträge: 42
Registriert: 29.10.2011 16:54

Re: Leistung mit THREADS geringer ohne?

Beitrag von ST4242 »

Vielleicht habe ich mich nicht richtig ausgedrückt.
Ich möchte im meiner Anwendung z.b. 10 Millionen Datensätze sortieren.
Deshalb habe ich eine Variante programmiert wobei der algorythmus jeweils 5 mio Datensätze sortiert einmal nacheinander und einmal eben mit 2 threads gleichzeitig. Wobei die ausführung mit 2 Threads länger dauern.
Dieses wird auch in meinen Beispiel deutlich hier arbeiten die Threads unabhängig voneinander eine störung über Mutexe oder ein gemeinsamer zugriff auf Ressourcen ist augeschlossen - und trotzdem arbeiten die Threads langsamer (Sobald mehr als einer gestartet wurde) - und dieses verhalten dürfte so nicht sein.

Beim obengenannten Beispiel heisst das: Sortien singlethread 20 s sortieren Multithread 25 s aber mit 2 Kernen.
Gruß Stefan
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Leistung mit THREADS geringer ohne?

Beitrag von ts-soft »

Du vergißt dabei aber, das die Libs Threadsicher laufen und somit langsamer sind, als ihre normale Version und zusätzlich natürlich
noch die Strings abgesichert werden. Das Du selber nichts absichern mußt, heißt ja nicht, das nichts abgesichert wird :wink:

Deshalb hat Dein Beispielcode auch nichts mit dem Problem zu tun, es wird kein Sortieralgoryhtmus, keine Datenbank oder ähnl.
genutzt.

Gruß
Thomas
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8820
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Leistung mit THREADS geringer ohne?

Beitrag von NicTheQuick »

@ts-soft: Mit Threadsicherheit hat das hier aber nichts zu tun. Es werden hier nur Integer benutzt innerhalb der Threads. Keine Strings oder sonstigen globalen Objekte.
Unter Linux sind alle Threads zusammen übrigens auch etwas langsamer.

Code: Alles auswählen

Ergebniss Single = 130336246
Ergebniss sThread= 129899741
Ergebniss Nr. 0   = 81112794
Ergebniss Nr. 1   = 62242999
Ergebniss Nr. 2   = 78911667
Ergebniss Nr. 3   = 89134570
Ergebniss Nr. 1  X= 70740494
Ergebniss Nr. 2  X= 54044321
Ergebniss Nr. 3  X= 77888882
Ergebniss Nr. 4  X= 79983729
Aber ich finde die Messmethode auch nicht so schlau, da 'ElapsedMilliseconds()' zu oft aufgerufen wird. Ich vermute, dass das der Flaschenhals ist. Am besten ist es, solche Tests mit echten Daten zu machen und 'ElapsedMilliseconds()' einmal davor und einmal danach aufzurufen. Mehr nicht.
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7035
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Leistung mit THREADS geringer ohne?

Beitrag von STARGÅTE »

Habe nun auch mal ein Test-Code geschrieben in dem 1000 Datensätze à 5000 Daten sortiert werden.

Code: Alles auswählen

Structure Test
	List String.s()
EndStructure

Global Dim Test.Test(1000)
Global ElapsedMilliseconds
Global Time1, Time2, Time4, Thread1, Thread2, Thread3, Thread4

; Liste Sortieren
Procedure Sort(Range)
	Protected I.i
	Protected First = PeekW(@Range)
	Protected Last  = PeekW(@Range+2)
	For I = First To Last
		SortList(Test(I)\String(), #PB_Sort_Ascending)
	Next
EndProcedure

;- Daten erzeugen
Procedure Init()
	Protected I, J
	For I = 1 To 1000
		ClearList(Test(I)\String())
		For J = 1 To 5000
			AddElement(Test(I)\String())
			Test(I)\String() = Str(Random(999999999))
		Next
	Next
EndProcedure

;- Daten nacheinander sortieren
Init()
ElapsedMilliseconds = ElapsedMilliseconds()
Sort(1 | 1000<<16)
Time1 = ElapsedMilliseconds()-ElapsedMilliseconds

;- Daten parallel (2) sortieren
Init()
ElapsedMilliseconds = ElapsedMilliseconds()
Thread1 = CreateThread(@Sort(),   1 |  500<<16)
Thread2 = CreateThread(@Sort(), 501 | 1000<<16)
WaitThread(Thread1)
WaitThread(Thread2)
Time2 = ElapsedMilliseconds()-ElapsedMilliseconds

;- Daten parallel (4) sortieren
Init()
ElapsedMilliseconds = ElapsedMilliseconds()
Thread1 = CreateThread(@Sort(),   1 |  250<<16)
Thread2 = CreateThread(@Sort(), 251 |  500<<16)
Thread3 = CreateThread(@Sort(), 501 |  750<<16)
Thread4 = CreateThread(@Sort(), 751 | 1000<<16)
WaitThread(Thread1)
WaitThread(Thread2)
WaitThread(Thread3)
WaitThread(Thread4)
Time4 = ElapsedMilliseconds()-ElapsedMilliseconds

;- Ergebnis
MessageRequester("Result", "Nacheinander: "+Str(Time1)+"ms"+#CR$+"Parallel (2): "+Str(Time2)+"ms"+#CR$+"Parallel (4): "+Str(Time4)+"ms")
---------------------------
Result
---------------------------
Nacheinander: 846ms
Parallel (2): 548ms
Parallel (4): 321ms
---------------------------
OK
---------------------------
Also ich sehe hier eine eindeutige Beschleunigung.
(ThreadSafe ON, Unicode ON, Debugger OFF)
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Re: Leistung mit THREADS geringer ohne?

Beitrag von Danilo »

NicTheQuick hat geschrieben:Unter Linux sind alle Threads zusammen übrigens auch etwas langsamer.
Vielleicht solltest Du nochmal nachrechnen, denn Deine kombinierten Thread-Ergebnisse sind immer größer als 'Single' oder 'sThread'.

Code: Alles auswählen

Ergebniss Single = 130.336.246

Ergebniss sThread= 129.899.741

Ergebniss Nr. 0   = 81.112.794
Ergebniss Nr. 1   = 62.242.999
Ergebniss Nr. 2   = 78.911.667
Ergebniss Nr. 3   = 89.134.570
------------------------------
Zusammen:          311.402.030

Ergebniss Nr. 1  X= 70.740.494
Ergebniss Nr. 2  X= 54.044.321
Ergebniss Nr. 3  X= 77.888.882
Ergebniss Nr. 4  X= 79.983.729
------------------------------
Zusammen:          282.657.426
'Single' zählt innerhalb von 5 Sekunden bis 130 Millionen.
Mit Threads zählt es innerhalb von 5 Sekunden bis 311 Millionen.
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Re: Leistung mit THREADS geringer ohne?

Beitrag von Danilo »

Habe den Originalcode mal leicht verändert, so dass in der Threadschleife lokale Variablen verwendet werden.
Die Testzeit habe ich auf 50 Sekunden erhöht und den Zähler auf Quad umgestellt, so dass es zu keinem
Überlauf kommen kann. Da ich auf einem Quad-Core Mac teste, benutze ich im ersten Thread-Test 8 Threads,
um einen eventuellen Effekt von HyperThreading zu sehen.

Benutzt wurde 64-bit PB, da 64-bit Prozessor.

Code: Alles auswählen

Ergebniss Single  = 1.064.846.281

Ergebniss sThread = 1.041.128.834

Ergebniss Nr. 0   =   754.338.305
Ergebniss Nr. 1   =   752.437.526
Ergebniss Nr. 2   =   754.295.498
Ergebniss Nr. 3   =   753.081.984
Ergebniss Nr. 4   =   753.376.076
Ergebniss Nr. 5   =   753.535.676
Ergebniss Nr. 6   =   755.067.599
Ergebniss Nr. 7   =   753.403.733
Zusammen:           6.029.536.397

Ergebniss Nr. 1  X= 1.024.426.606
Ergebniss Nr. 2  X= 1.024.166.873
Ergebniss Nr. 3  X= 1.024.517.785
Ergebniss Nr. 4  X= 1.024.780.033
Zusammen:           4.097.891.297
Auf einem Quad-Core mit Hyperthreading kann ich - bei diesem Test - innerhalb 50 Sekunden also knapp das 6-fache machen als mit Single-Thread.

<Edit>
Habe es nochmal mit PB 32-bit laufen lassen:

Code: Alles auswählen

Ergebniss Single  =   967.107.479

Ergebniss sThread =   972.459.304

Ergebniss Nr. 0   =   664.889.688
Ergebniss Nr. 1   =   666.529.855
Ergebniss Nr. 2   =   664.658.905
Ergebniss Nr. 3   =   665.666.976
Ergebniss Nr. 4   =   664.022.776
Ergebniss Nr. 5   =   665.744.919
Ergebniss Nr. 6   =   666.812.997
Ergebniss Nr. 7   =   667.225.343
Zusammen:           5.325.551.459

Ergebniss Nr. 1  X=   966.806.310
Ergebniss Nr. 2  X=   966.807.942
Ergebniss Nr. 3  X=   966.906.873
Ergebniss Nr. 4  X=   966.680.401
Zusammen:           3.867.201.526
</Edit>


Der leicht angepasste Code:

Code: Alles auswählen

; Testprogramm für die Leistungmessung bei Nutzung von Threads
Structure thMEM
    zaehler.q
    zaehler2.i
    zeitInMS.i
    thid.i
EndStructure

Procedure zaehlenbis(*m.thmem)
    Protected t, ms, zaehler.q
    t=ElapsedMilliseconds()
    ms=*m\zeitInMS
    Repeat
        zaehler+1
        zaehler2+2
        zaehler2=zaehler*zaehler2
        zaehler2/2
        zaehler2=0
    Until ElapsedMilliseconds()-t>ms
    *m\zaehler = zaehler
EndProcedure


Dim mem.thmem(30)
Define erg.s,used.i=7
mem(0)\zeitInMS=50000

zaehlenbis(@mem(0))
i=0
erg=erg+"Ergebniss Single  = "+Str(mem(i)\zaehler)+Chr(10)+Chr(13)
mem(0)\zaehler=0
mem(0)\thid=CreateThread(@zaehlenbis(),@mem(0))
WaitThread(mem(0)\thid)
erg=erg+"Ergebniss sThread = "+Str(mem(i)\zaehler)+Chr(10)+Chr(13)

For i=0 To used
    mem(i)\zeitInMS=mem(0)\zeitInMS
    mem(i)\zaehler=0
Next i
For i=0 To used
    mem(i)\thid=CreateThread(@zaehlenbis(),@mem(i))
Next
For i=0 To used
    If mem(i)\thid:WaitThread(mem(i)\thid):EndIf
Next
For i=0 To used
    erg=erg+"Ergebniss Nr. "+Str(i)+"   = "+Str(mem(i)\zaehler)+Chr(10)+Chr(13)
Next i

zusammen.q = 0
For i=0 To used
    zusammen + mem(i)\zaehler
Next i
erg=erg+"Zusammen:          "+Str(zusammen)+Chr(10)+Chr(13)

Define m1.thmem,m2.thmem,m3.thmem,m4.thmem
m1\zeitInMS=mem(0)\zeitInMS
m2\zeitInMS=mem(0)\zeitInMS
m3\zeitInMS=mem(0)\zeitInMS
m4\zeitInMS=mem(0)\zeitInMS
m1\thid=CreateThread(@zaehlenbis(),@m1)
m2\thid=CreateThread(@zaehlenbis(),@m2)
m3\thid=CreateThread(@zaehlenbis(),@m3)
m4\thid=CreateThread(@zaehlenbis(),@m4)
WaitThread(m1\thid)
WaitThread(m2\thid)
WaitThread(m3\thid)
WaitThread(m4\thid)
erg=erg+"Ergebniss Nr. 1  X= "+Str(m1\zaehler)+Chr(10)+Chr(13)
erg=erg+"Ergebniss Nr. 2  X= "+Str(m2\zaehler)+Chr(10)+Chr(13)
erg=erg+"Ergebniss Nr. 3  X= "+Str(m3\zaehler)+Chr(10)+Chr(13)
erg=erg+"Ergebniss Nr. 4  X= "+Str(m4\zaehler)+Chr(10)+Chr(13)
erg=erg+"Zusammen:          "+Str(m1\zaehler+m2\zaehler+m3\zaehler+m4\zaehler)+Chr(10)+Chr(13)

MessageRequester("Ergebnisse",erg)
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Leistung mit THREADS geringer ohne?

Beitrag von ts-soft »

NicTheQuick hat geschrieben:@ts-soft: Mit Threadsicherheit hat das hier aber nichts zu tun. Es werden hier nur Integer benutzt innerhalb der Threads. Keine Strings oder sonstigen globalen Objekte.
Ich sprach auch nicht von dem Beispielcode, der mit dem Beispiel rein garnichts am Hut hat.
Da wird nichts sortiert oder ähnlich. Ich bin von dem ausgegangen,
was der Problembeschreibung entspricht (theoretischer Weise, wie so meist). Entsprechender Code fehlt hier leider gänzlich :mrgreen: .

STARGÅTE hat einen entsprechenden Beispielcode nachgeliefert, der wenigstens etwas relevance zum Problem hat :allright:

Gruß
Thomas
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Antworten