Wieviele Threads sind sinnvoll?

White_Fox

Top Contributor
Ein schönes Wochenende allerseits.

Ich hätte mal zwei Fragen zu Threads:
  1. Wieviele parallele Threads erachtet ihr für sinnvoll?
  2. Ich hätte zu 1. gesagt: ein Thread je Rechenkern, wenn diese Hyperthreading unterstützen auch zwei. Das bringt mich zu der Frage: Wie kann ich in einem Javaprogramm herausfinden, wieviele Rechenkerne ich zur Verfügung habe?

Gruß
White_Fox
 
Das hängt hauptsächlich mal von der zu lösenden Aufgabe und deren Parallelisierbarkeit und der arithmetischen Dichte (Prozessorzyklen pro I/O) der Aufgabe ab. Wenn du zu nahezu 100% auf I/O wartest und du kein non-blocking Modell fährst, dann können auch 100 Threads was bringen.
Z.B. ist das der Fall bei einem Servlet-Container wie etwa Tomcat, die nach dem Thread-pro-Request-Modell arbeiten und somit schon nahezu zu 100% I/O-bound und nicht compute-bound sind. Wenn deine Aufgabe compute-bound ist (du also eine hohe arithmetische Dichte, also viele nutzbare Prozessorzyklen pro I/O) hast, dann bringen nur soviele Threads etwas wie viele Kerne du hast.
Zu der Frage, wie man die Anzahl logischer Prozessoren findet: https://stackoverflow.com/questions/4759570/finding-number-of-cores-in-java
 
Ich denke, dass in https://stackoverflow.com/questions...umber-of-threads-in-parallel-programs-in-java eine sehr gute Zusammenfassung in der Antwort von emon ist.

Die Frage ist aber, in wie weit es notwendig ist, sowas selbst zu schreiben. Gewisse Dinge sind ja bereits implementiert.

So wäre z.B. denkbar, die zu verarbeitenden Daten über einen parallelen Stream zu bearbeiten. Wobei parallele Streams auch nur auf ForkJoinPool.commonPool zurückgreifen. Und der Pool hat nach meinem Wissen (habe ich jetzt nicht nachgeschlagen) 1 Thread weniger als eben "Processors" zur Verfügung stehen. (Das sind logische CPUs, also auch incl. Hyper Threading).

Sollte ich mich hier irren, so wird hoffentlich ein Experte mich korrigieren können.

Und ganz Wichtig: Den commonPool nicht mit Threads belegen, die blockieren. Der wird halt für gewisse Verarbeitungen benutzt und den würde ich in der Regel nicht blockieren.
 
Ich werde mir mal parallele Streams anschauen, aber ich denke nicht daß ich da auf viel Fertiges werde zurückgreifen können. Beim Serialisieren geht es darum, alle Descriptorobjekte in Bytearrays umzuwandeln, das macht die meiste Arbeit aus. Danach alle Bytearrays zusammenzupappen ist rasch erledigt.
Aber das Serialisieren ist auch ein eher nachrangiger Aspekt:

Der mit richtig großem Abstand meiste Aufwand kommt beim Zusammenbauen der Objete zu stande (da halt viele Objekte instanziert), ich weiß aber nicht ob ich da nur mit parallelen Threads viel raushole. Wahrscheinlich werde ich mich auch noch damit beschäftigen müssen, wie ich Speicher im vorraus alloziiere, falls das in Java überhaupt geht.

Und auch das Analysieren von Objekten ist - wenn auch geringfügig - zeitintensiver als der Serialisierungskram. Das werde ich vllt. als erstes Multithreaden.

Ich habe mal einen Test geschrieben und die Zeit gestoppt, welcher Vorgang wie lange dauert. Daher kommt Serialisierung/Deserialisierung erst ganz am Ende dran. 🙂
 
Die parallelen Streams waren nur eine Option, die ich genannt habe, weil ich gerne bei diversen Aufgaben Streams nutze.

Aber die parallelen Streams nutzen halt den commonPool von ForkJoinPool (https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ForkJoinPool.html)

Die Nutzung zeigt z.B. etwas https://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html, aber die Dokumentation enthält auch ThreadPools und so - evtl. schaust du da einfach etwas durch die Topics im Seitenmenü.

Oder weitere Links (gerade weil manche die Oracle Dokumentation als zu kurz oder so empfinden):
Oder YouTube (nicht wirklich geprüft - nur vom Titel her halt gefunden):

Vielleicht ist da einfach etwas für Dich dabei, das Dir die Arbeit / Umstellung erleichtert (So diese Ideen in Deinen Augen zielführend sind! Da wird auch nichts magisches gemacht - du kannst also auch die Anzahl der Prozessoren ermitteln ( Runtime.getRuntime().availableProcessors(); ) und dann einfache Threads selbst erstellen und verwalten oder so. Es gibt bestimmt ganz viele Möglichkeiten, die alle ihre Berechtigung haben. Ich wollte halt nur die Idee aufbringen, dass die manuelle Begrenzung an Threads ggf. nicht notwendig ist.)
 
Ich stöber das mal durch...ich lerne ja gerne dazu. 🙂

Und vielleicht stell ich das auch mal etwas detaillierter hier rein - die nächste Revision werde ich hier jedenfalls wieder zur Begutachtung vorlegen. Mir hat das Feedback und die Hilfestellungen hier jedenfalls sehr viel gebracht.
 
Grundsätzlich musst du natürlich berücksichtigen, wenn die Threads auf gemeinsamen Objecten/Collections arbeiten, dass der Zugriff da nicht in Probleme läuft. Insbesondere bei Sachen wie: "Prüfe ob schon ein Eintrag vorhanden, wenn nein füge eine hinzu" läuft man im Multithreading leicht in häßliche Probleme rein, wenn nicht aufpasst. Entweder hat man Duplikate drin oder baut sich Performance-Probleme, wenn man zu viel synchronized nutzt.
 
Jap, diese Probleme kenne ich aber glücklicherweise schon. 🙂

Ich hab mal eine Klasse gebaut die mit einer Hardware in "Echtzeit" (Haha, Witz komm raus...) kommunizieren sollte. Da haben insgesamt drei Threads miteinander auf gemeinsamen Daten gewerkelt und an einer Stelle wurde die Zugriffsberechtigung ignoriert, am Ende habe ich per Reflection untersuchen müssen, welcher Thread da aus der Reihe tanzt.
 

Zurück
Oben