Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

Zeus

Frischling

  • »Zeus« ist der Autor dieses Themas

Beiträge: 83

Beruf: Schule

  • Private Nachricht senden

1

30.05.2011, 03:15

Multithread Performance in C#

Guten Abend allerseits,

im Moment arbeite ich an einer Physiksimulation.

Beim Berechnen und dastellen der Szenerie hat sich bereits vor einigen Tagen das Problem aufgetan das die Performance unter aller Sau war. Ein Umstieg auf DX im Grafikbereich sorgte dafür das die Zeichengeschwindigkeit nun unabhängig von dem dazustellenden unter 20ms liegt (also ausreichend).

Am nächsten Tag stellte sich raus das die Updatezyklen für die Logik viel zu lang sind, also teilte ich den Grafik und den Logikteil in unabhängige Blöcke indem ich die Grafik an ein Timer (Interval 25ms) und die Logik an ein BackgroundWorker hängte. Dies funktionierte sehr gut solange die Objekt Anzahl unter 20 lag und alles wurde flüssig dagestellt. Wollte ich mehr Objekte traten ruckler auf. Daraufhin spendierte ich jedem Objekt das berechnet werden muss einen eigenen Thread. Dies steigerte zwar die Leistung für große Objektmengen sichtbar, von flüssiger Bewegung ist aber seit dem nicht mehr zu sprechen. Eine Zeitmessung aller Objekte hat ergeben das die Updatezeit stark schwankt (zwischen 5 und 100ms) sich aber zumeist um die 30ms befindet. Trotz der passablen durchschnittlichen Geschwindigkeit haben die längeren Updatezeiten einen sehr unschönen optischen Eindruck zufolge. Es sieht aus als würde die Anwendung "stocken". Was mich nun daran wundert ist die Tatsache das mein CPU (4x2.8 Ghz) nur bei ca. 30 - 40 % Last liegt und das bevor ich auf die einzel Threads umgestiegen bin alles flüßig lief (unterhalb der 20 Objekt Grenze). Die Anwendung könnte also mehr Leistung in Anspruch nehmen. Warum tut sie es nicht ?

Was ich euch da an Code zeigen soll weis ich auch nicht da es mehr ein allgemeines Problem ist. Also lasse ich es mal bis jamand fragt.

Über eine Antwort würde ich mich sehr freuen

Mfg Zeus
Ich würde die Welt gerne verbessern, doch Gott gibt mir den Quellcode nicht!

Sprachen: C,C++/CLI,C#,ASM,PHP,Java(-script) ... fürn Anfang auch genug ...

Mein letztes Projekt:

http://www.youtube.com/watch?v=vU14ewcVaXU

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

2

30.05.2011, 03:28

Ich vermute mal dass der Synchonisationsaufwand einfach zu hoch ist!? Du kannst noch so viele Threads auf das Problem werfen, wenn dein System soviele Synchronisierungspunkte hat dass am Ende wieder alles mehr oder weniger Serialisiert wird dann ist das einzige was die Threads gebracht haben massiver Overhead. Ohne dein System zu kennen kann man da schwer irgendwas sagen. Beschreib eben mal wie du prinzipiell vorgehst. Um was für Objekte handelt es sich da? Wie genau arbeiten Logik und Grafik zusammen? ...

Zeus

Frischling

  • »Zeus« ist der Autor dieses Themas

Beiträge: 83

Beruf: Schule

  • Private Nachricht senden

3

30.05.2011, 04:07

Danke für die schnelle Antwort zu so später Stunde :)

Hmmmm ... Ist der Aufwand um eine List<> zu übergeben so hoch das soviel Overhead entstehn kann ? ... Ich habe auch schon darüber nachgedacht die Idee dann aber wieder vorworfen. Im gesamten Projekt verwende ich nur 2 Locks als Schutz für die zentrale List<>. Ich dachte das es bei deisem Szenario nicht wichtig ist alles Synchron zu halten.

Also gut ... zum Aufbau.

Die Grafik fragt in jedem Updatezyklus bei der Logik nach den Elementen die gezeichnet werden müssen. Diese gibt eine Liste mit allen Elementen zurück und die Grafik zeichnet.

Die Logik fragt zu keinem Zeitpunkt bei der Grafik nach irgentetwas.

Die einzelnen Entitäten fragen in jedem Updatezyklus bei der Logik nach allen Elementen (Ich dachte es ist besser dem Einzelthread die Kollisionsbrechnung zu überlassen als es von der Logik berechnen zu lassen die in dem Fall an der Stelle wieder serialisierend wäre). Die Entität berechnet mit welchen sie kollidiert und ändert daraufhin ihre Bewegung. Eine Rückgabe oder Rückschreiben von Werten in die Logik ist nicht erforderlich da der Thread an der Updatefunktion der Objekte hängt die die Logik eh schon verwaltet bzw in ihrer Liste hat.

C-/C++-Quelltext

1
2
3
4
5
public List<Sphere> getPhysX() 
{      lock (this.mLock) 
      {           return new List<Sphere>(this.mP); 
      }
}


Das ist die Funktion die die jeweiligen Objekte zurückgibt. Die Bearbeitungszeit liegt mindestens bei 0ms und maximal bei 0ms. Deshalb habe ich die Funktion ansich ausgeschlossen als Schlüsselloch.
Ich würde die Welt gerne verbessern, doch Gott gibt mir den Quellcode nicht!

Sprachen: C,C++/CLI,C#,ASM,PHP,Java(-script) ... fürn Anfang auch genug ...

Mein letztes Projekt:

http://www.youtube.com/watch?v=vU14ewcVaXU

Zeus

Frischling

  • »Zeus« ist der Autor dieses Themas

Beiträge: 83

Beruf: Schule

  • Private Nachricht senden

4

30.05.2011, 04:07

Sorry Doppelposting -> Bitte entfernen
Ich würde die Welt gerne verbessern, doch Gott gibt mir den Quellcode nicht!

Sprachen: C,C++/CLI,C#,ASM,PHP,Java(-script) ... fürn Anfang auch genug ...

Mein letztes Projekt:

http://www.youtube.com/watch?v=vU14ewcVaXU

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

5

30.05.2011, 07:05

Ich hoffe das Programm wurde als Release kompiliert und nicht im Debug-Mode ausgeführt? ;) Klingt albern, aber die Performanceunterschiede sind mehr als drastisch und es wird gern mal vergessen. Allerdings verwunderlich, dass die reine Spiellogik so langsam ist, das Problem hatte ich meist eher beim Rendering.

Die Ausführung einer einzelnen Basis-Operation sollte so gut wie immer 0ms sein. Es ist nicht sinnvoll eine einzelne Zeile Code so zu messen. Generell solltest Du erstmal rausfinden, welcher Schritt Deiner Logik überhaupt so komplex ist und lange dauert. Eventuell kannst Du diesen dann optimieren. Ohne konkretere Angaben lässt sich Dein Problem jedenfalls so nicht von uns beheben - außer natürlich die generellen Fehler wie dot schon sagte: Hunderte Threads machen die Sache nicht besser, sondern schlechter. Letztendlich hat Deine CPU ja auch keine Hundert Kerne, sondern muss die Threads ja doch wieder nacheinander ausführen und bekommt dann zusätzlich noch den Thread-Switch-Overhead als Aufwand dazu. Ich würde maximal mit 4 Threads alles in allem arbeiten an Deiner Stelle.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »BlueCobold« (30.05.2011, 07:14)


6

30.05.2011, 08:25

ich weiß ja nicht, ob dus schon probiert hast, aber es gibt da ein gutes tool mit dem du messen kanns wie lang und oft dein programm in welcher funktion ist... damit findet man sehr schnell solche flaschenhälse...

NProof heißt das.

lg

Beiträge: 721

Wohnort: /dev/null

Beruf: Software-Entwickler/Nerd

  • Private Nachricht senden

7

30.05.2011, 08:59

Threads am besten mit der Anzahl der Kerne skalieren, da hast du dann optimierte "möglich" Nebenläufigkeit. Welche D3D-Version nutzt du?

Nox

Supermoderator

Beiträge: 5 272

Beruf: Student

  • Private Nachricht senden

8

30.05.2011, 09:36

Wenn du schon mit Threading arbeiten willst, hier ein paar Tipps.

-Faustregel für optimale Performance: Threadanzahl = "core"anzahl
-es gibt für sowas ThreadPools
-ein Job in einem ThreadPool darf nicht zu klein sein (hohe Verluste durch Overhead) aber auch nicht zu groß (Threadpool kann dann ggf nicht mehr die Last gescheit balanzieren). Die optimale Anzahl an Objekten pro Job findet man nur durch ausprobieren.

Falls du lieber das Grundproblem lösen willst, könntest du von Intel die 30 (oder waren es 60) Tage Testversion von deren Performance Analizers runterladen und installieren. Der ist nämlich sehr gut um Flaschenhälse zu finden.
PRO Lernkurs "Wie benutze ich eine Doku richtig"!
CONTRA lasst mal die anderen machen!
networklibbenc - Netzwerklibs im Vergleich | syncsys - Netzwerk lib (MMO-ready) | Schleichfahrt Remake | Firegalaxy | Sammelsurium rund um FPGA&Co.

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

9

30.05.2011, 12:12

-Faustregel für optimale Performance: Threadanzahl = "core"anzahl

Das gilt nur wenn deine Threads nicht I/O bound sind, was bei dir aber wohl zutrifft.

Zeus

Frischling

  • »Zeus« ist der Autor dieses Themas

Beiträge: 83

Beruf: Schule

  • Private Nachricht senden

10

31.05.2011, 01:13

Danke für eure vielen Antworten.

Das Problem schien tatsächlich am Overhead gelegen zu haben. Ich habe es jetzt wieder umgestellt auf Seriell und die Bewegungen sind wieder flüssig -> allerdings geht die Performance in die Knie wenn mehrere Objekte auf dem Feld sind. Den Seriellen Teil auf mehrere Threads aufzuteilen ohne jedem Objekt einen eigenen zu geben scheint mir aber im Moment nicht Möglich. Da muss ich dann nochmal ganz neu übers Grundgerüst nachdenken bzw nachschauen ob ich es auf ThreadPools verteilt bekomme ...

@BlueCobold: Nein war es nicht. Da ich mit diesem Projekt auf C# 2010 umgestiegen bin habe ich erstmal suchen müssen wo und wie ich die Release finde.

@SupremeDeveloper: Ich benutze die DX SDK 2010 June

Danke fürs Helfen

Zeus
Ich würde die Welt gerne verbessern, doch Gott gibt mir den Quellcode nicht!

Sprachen: C,C++/CLI,C#,ASM,PHP,Java(-script) ... fürn Anfang auch genug ...

Mein letztes Projekt:

http://www.youtube.com/watch?v=vU14ewcVaXU

Werbeanzeige