Threading und Performance

  • Allgemein

Es gibt 12 Antworten in diesem Thema. Der letzte Beitrag () ist von φConst.

    Threading und Performance

    Hallo,

    es gibt in vb.net zum Beispiel parallel.foreach.
    Also das Prinzip mehrere Dinge nicht nacheinander, sondern parallel ablaufen zu lassen.

    Dabei frage ich mich inwiefern spielt z.B. die Größe der Schleife einer Rolle?
    Man kann ja nicht 20000 Dinge parallel laufen lassen. Irgendwo gibt ja auch die Grenzen des ausführenden Computers.

    Manche Maschinen können mehr, manche weniger. Wie finde ich das raus? Womit hängt das zusammen?
    Was passiert wenn ich mehr versuche als möglich ist?
    Vielleicht könnt ihr mir dazu auch etwas Literatur empfehlen.

    Viele Grüße
    Die Schleife partitioniert die Quellsammlung und plant die Arbeit basierend auf der Systemumgebung in mehrere Threads ein.
    Je mehr Prozessoren das System aufweist, desto schneller wird die parallele Methode ausgeführt.
    Bei manchen Quellsammlungen ist eine sequenzielle Schleife je nach Größe der Quelle und Art der Arbeit, die die Schleife ausführt, möglicherweise schneller.

    docs.microsoft.com/de-de/dotne…ple-parallel-foreach-loop
    docs.microsoft.com/de-de/dotne…ism-task-parallel-library
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    Hängt aber auch davon ab, was du ausführen möchtest (zum Beispiel: Werte Berechnung vs. Datentransfer übers Netzwerk).
    Je nach Anwendungsgebiet, würde ich den Parameter MaxDegreeOfParallelism für den Endanwender konfigurierbar machen.

    Haudruferzappeltnoch schrieb:

    Man kann ja nicht 20000 Dinge parallel laufen lassen.
    Das organisiert das System bzw. das Framework.
    Wichtig ist, dass Du einen Prozessor mit vielen Kernen hast, auf die dann die Aufgaben verteilt werden.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Sollte man denn generell einer parallel Schleife vertrauen oder bietet es sich an, basierend auf den Kernen die zur Verfügung stehen, selbst eine Parallelisierung durchzuführen.

    Man könnte ja statt 20000 Elementen parallel laufen lassen bzw. 20000 Elemente sequenziell laufen lassen, z.B. auch sequeziell 5000mal 4 Elemente parallel laufen lassen.
    Gibts da vielleicht tiefere Beschäftigungen wie man eine gegebene Aufgabe am Besten aufteilen sollte in Abhängigkeit zum vorliegenden Rechensystem?
    Eben wie ihr schon sagtet, dass manche Systeme theoretisch auch sequenziell schneller laufen würden.

    Oder würdet ihr sagen da ist eher ein Trial and Error Ansatz gefragt?
    Es wird darauf hinauslaufen, dass das Betriebssystem das organisiert. Solange Du weniger Aufgaben als gelangweilte Kerne hast, dürfte sich Dein Aufgabenpaket auf eben jene Kerne gleichmäßig verteilen lassen. Sollten es mehr Aufgaben sein als gelangweilte Kerne existieren, muss eben jeder freie Kern mehrere Aufgaben - nacheinander - abarbeiten. Ich arbeite zwar tatsächlich wenig damit. Aber grundsätzlich wär das wohl sinnvoll, wenn Du 2-8 komplexe Aufgaben hast, die nebeneinander her unabhängig voneinander verarbeitet werden können. Ansonsten wird es sich wohl mit dem Nutzen in Grenzen halten.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Haudruferzappeltnoch schrieb:

    Oder würdet ihr sagen da ist eher ein Trial and Error Ansatz gefragt?
    Zunächstmal ist ein konkretes Problem gefragt.
    So in der Theorie besprochen und beschlossen erweisen sich Dinge meist inne Praxis als Humbug.
    Und dass man nicht optimieren soll ist dir bekannt, ja?
    Und ich schau immer, wenns unvermeidbar wwird, was zu optimieren, nach einem besseren Algorithmus. Weil 4 Kerne - boah! da wirds vlt. dreimal schneller.
    Wenn sich ein besserer Algo findet wirds aber 100mal oder 1000mal schneller - und ohne Threading.

    Also wie gesagt: Hast du ein konkretes Problem, was nur mit Threading zu lösen ist (und wäre eine 3fache Performance ühaupt genug (wie gesagt: ist nicht eben viel))?

    Haudruferzappeltnoch schrieb:

    Oder würdet ihr sagen da ist eher ein Trial and Error Ansatz gefragt?

    Ich würde sagen dass die ​Parallel.ForEach schon mal gar nicht schlecht ist. Habe ich auch schon mal verwendet, aber nur selten. Es ist schwer einen guten Anwendungsfall zu finden, also grundsätzlich für Parallelisierung. Aber da versucht das .NET schon mal die beste Menge an Workern zu benutzen, sodass das System gut ausgelastet wird. Dazu darf die einzelne Arbeit aber nicht zu klein sein. Das Parallelisieren hat einen gewissen Overhead und die Arbeit muss da deutlich überwiegen, sonnst hat es keinen positiven Effekt. Aber so oder so ​Trial and Error wirst du hier viel machen müssen um zu schauen, ob die Stelle geeignet ist und entsprechend viel bringt.

    ErfinderDesRades schrieb:

    Und dass man nicht optimieren soll ist dir bekannt, ja?
    Hab ich noch nie verstanden, also die Aussage so generell stehen zu lassen. Wieso? Klar soll man nicht Overengineering-Betreiben und was man schätzt ist meistens nicht ganz richtig, aber die Aussage so ist schon heftig.
    "Optimieren" ist ein Begriff, und hat eine Definition: Etwas (in irgendeiner Hinsicht) besser machen unter InKaufnahme von Verschlechterungen in anderer Hinsicht.
    Üblicherweise verbessert man die Performance und nimmt dafür in Kauf, dass ursprünglich einfacher Code nachher umständlich, unleserlich, schlecht wartbar ist.
    Und das trifft auch hier zu.
    Nun ist nunmal Lesbarkeit von Code das allerwichtigste.
    Also nur Optimieren, wenns ganz konkret ist, und wenns anders absolut nicht mehr geht.
    Dazu gibts noch eine Regel: Man soll es zuletzt tun.
    "Premature Optimizazion is the Source of all evil" (den Satz kannste auch googeln).
    Weil Optimierung wirkt sich meist negativ aus auf die Architektur.
    Gute Architektur ist aber die allerbeste Vorraussetzung erfolgreicher Optimierung.
    Also verfrühte Optimierung blockiert spätere, bessere Optimierung.

    Übrigens: Eine Verbesserung, die gelingt, ohne Nachteile in kauf zu nehmen, ist keine Optimierung, sondern eine Verbesserung.
    Solch ist natürlich jederzeit willkommen.

    ErfinderDesRades schrieb:

    Eine Verbesserung, die gelingt, ohne Nachteile in kauf zu nehmen, ist keine Optimierung, sondern eine Verbesserung.
    Wenn Du das so definierst …
    Duden (Optimierung -> optimieren -> optimal) und Wiktionary haben da eine andere Meinung. Da heißt es (bei Duden sinngemäß) das bestmögliche Ziel erreichen bzw. Wiktionary: Verbesserung der Qualität. Dass man da eine Gewichtung der zu erreichenden Ziele vornehmen muss, steht sogar bei(m) Duden explizit. Dass man jenes Gewichtungsziel selber festlegen muss, folgt daraus. Aber nicht, dass es bei der Codeausführung um Geschwindigkeit geht. Man kann einen Code - wie Du selbst schreibst - auch auf Lesbarkeit/Verständnis verbessern alias optimieren. Da eine fixe Verknüpfung zwischen »Optimieren« und Geschwindigkeit der Codeausführung (oder gar Länge/Kürze des Codes?) herbeizupostulieren, fände ich zu pauschal.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    ja, das ist ein bischen Coder-Begrifflichkeit.
    In anderen Kontexten mag man unter Optimierung einfach Verbesserung verstehen - ich würde sehr Wert drauf legen, das zu unterscheiden, zumindest beim Coden (aber gerne auch sonst).
    googelt doch mal bischen, was andere Coder zu Optimizazion zu sagen haben - google etwa "3 rules of optimizazion"

    Aber ich wills auch nicht zerlabern. Werft "Optimierung" und "Verbesserung" in einen Topf, optimiert was und soviel ihr wollt, nach Kriterien, die wichtiger sind als Wartbarkeit, und macht eure Erfahrungen damit oder auch nicht.



    Und hiermit erteile ich Ihnen das letzte Wort:
    Nehmt euch ein Zimmer :P

    Also für mich ist die Lesbar- und Wartbarkeit des Codes inzwischen auch am Wichtigsten. Dahingehend "optimiere" ich mein Programm aktuell wo immer mir etwas auffällt.

    Aber generell bin ich dabei: Funktionalität sollte vor Performance im Vordergrund stehen. Für mich spricht aber nix dagegen (auch während der Entwicklung) auch an der Performance zu
    schrauben, solange die Funktionalität gegeben bleibt und eben auch Wartung und Lesbarkeit. Man sollte ja als Entwickler auch nach längerer Zeit Abstinenz noch verstehen, was man damals da gecodet hat.

    Es gibt aber noch die andere Seite: Lernen und Verständnis für andere/neue Dinge aufbringen. Es könnte also sein, dass ich z.B. gerade keinen Bock auf meine Anwendung hab
    und zieh' mir z.B. 1-2 Stellen davon raus und schau' in nem separaten Projekt wie ich was anders und ggf. auch performanter machen könnte...

    Das wäre jetzt mein Weg :rolleyes: :thumbup:

    PS: Parallel.ForEach hat mir bis zur Erstellung des Threads hier z.B. nix gesagt - werd ich aber bestimmt mal testen
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Dabei frage ich mich inwiefern spielt z.B. die Größe der Schleife einer Rolle?

    Intern wird wird es wahrscheinlich in etwa doppelt so viele Threads geben, wie dein Rechner logische Kerne hat (wobei das abhängig von der Länge der Queue ist). Die Aufgaben (die Action<T> die die übergibst) werden dann auf diese Threads verteilt. Wahrscheinlich verwendet das Framework sowas wie eine "Work-Stealing-Threadpool": Jeder Thread verfügt dann über eine Queue, um sich die nächste Aufgabe zu holen. Ist ein Thread idle, hat also nichts zu tun, "stiehlt" er die Aufgabe eines anderen Threads.

    Die Größe der Schleife spielt also insofern eine Rolle, dass die Anzahl der Aufgaben pro Thread wahrscheinlich #Schleifen_Durchläufe/(#Kerne*2) sein wird.

    Wie finde ich das raus? Womit hängt das zusammen?

    Hat viele Faktoren, besonders, wie viele logische Kerne zur Verfügung stehen ( docs.microsoft.com/en-us/dotne…fparallelism?view=net-6.0) sowie wie schnell die Kerne jeweils sind.
    Und Gott alleine weiß alles am allerbesten und besser.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „φConst“ ()