Seite 1 von 2

Leistung mit THREADS geringer ohne?

Verfasst: 14.03.2015 20:00
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)
  
 

Re: Leistung mit THREADS geringer ohne?

Verfasst: 14.03.2015 20:51
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

Re: Leistung mit THREADS geringer ohne?

Verfasst: 14.03.2015 21:08
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.

Re: Leistung mit THREADS geringer ohne?

Verfasst: 14.03.2015 21:49
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

Re: Leistung mit THREADS geringer ohne?

Verfasst: 14.03.2015 21:58
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

Re: Leistung mit THREADS geringer ohne?

Verfasst: 14.03.2015 23:05
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.

Re: Leistung mit THREADS geringer ohne?

Verfasst: 15.03.2015 00:46
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)

Re: Leistung mit THREADS geringer ohne?

Verfasst: 15.03.2015 01:06
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.

Re: Leistung mit THREADS geringer ohne?

Verfasst: 15.03.2015 02:34
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)

Re: Leistung mit THREADS geringer ohne?

Verfasst: 15.03.2015 04:16
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