Java - wie man Threads in einem Prozess implementiert, der auf Daten wartet [geschlossen]

8

Ich bin ziemlich neu in der Multithread-Programmierung und hoffte, einen Einblick in die beste Art zu erhalten, die folgende Idee umzusetzen.

Im Moment funktioniert mein Code so

Es ist ein singulärer Thread, so dass in der Zeit, die es braucht, um jedes Stück Daten zu verarbeiten und in die Datenbank zu schreiben, neue Daten hereinkommen und in die Warteschlange gestellt werden, was die Dinge zu sehr verlangsamt. Ich bin auf einem 4CPU-Server ausgeführt, aber das aktuelle Setup verwendet nur 1.

Ich möchte die Arbeit im mittleren Teil über die restlichen 3 CPUs trennen. Wie würde ich das am besten machen? Ich dachte, dass ich für jedes neue Datenstück einen neuen Thread erstellen könnte, aber wir sprechen im Laufe eines Tages Hunderttausende neuer Threads. Nach dem, was ich gelesen habe, wäre der damit verbundene Overhead sehr groß. Die Erinnerung ist eine Sorge für mich, wenn die Erschaffung all dieser Fäden zu viel Erinnerung isst, werde ich in Schwierigkeiten geraten. Stimmt es, dass ein neuer Thread eine weniger ausgelastete CPU verwendet oder dieselbe verwendet, da es sich um die gleiche JVM handelt?

Die Verarbeitung und der DB-Schreibvorgang für jedes neue Datenstück sollte nicht länger als ein paar Sekunden dauern.

Ich habe auch über Thread-Pools gelesen, aber die Idee ist für mich etwas verwirrend und ich kann kein großartiges Beispiel finden.

Ich habe so etwas gedacht

Bitte helfen Sie ein Multi-Thread-Newb out in einem vernünftigen Design! Vielen Dank im Voraus: -)

    
Marianna 11.12.2012, 20:54
quelle

2 Antworten

5

Der wichtigere Punkt wäre, wie viele Threads parallel arbeiten (und damit möglicherweise eine Maschine töten). Wenn Sie ein Thread-Objekt nach dem anderen erstellen, könnte es effizienter gemacht werden, aber im Allgemeinen sind die Kosten dafür (wahrscheinlich) vernachlässigbar (wie Michal betonte). Wenn Sie das beiseite lassen (und davon ausgehen, dass Sie etwas über Multi-Threading lernen wollen), klingt Ihr Design bereits vernünftig genug. Sehen Sie sich an, was java.util.concurrent kann gebe dir Respekt vor Werkzeugen, um es zu erreichen:

  • ExecutorService : Wäre die beste Wahl. Erstellen Sie einen festen Thread-Pool von n worker threads und geben Sie dann für jeden eingehenden Thread einen Runnable ein, der Ihre Daten verarbeitet und alle Daten in der Datenbank speichert.

    %Vor%

    Das ExecutorService stellt sicher, dass nur die feste Anzahl von Arbeitern parallel läuft,

  • Eigener Warteschlangenmechanismus: Wenn es sich um Jobs mit unterschiedlichen Prioritäten handelt, möchten Sie vielleicht Ihren eigenen Arbeitsmechanismus implementieren. Beachten Sie, dass dies viel komplizierter ist, und Sie sollten sich wahrscheinlich an die ExecutorService -Lösung halten, wenn dies möglich ist.

    Die Grundidee besteht darin, ein BlockingQueue zu haben, zu dem Daten hinzugefügt werden, und n worker threads zu starten, die Sie aus der Warteschlange der Jobs gelesen haben. Der Trick besteht darin, dass die Warteschlange blockiert, wenn keine Jobs vorhanden sind (wodurch die Threads in den Ruhezustand versetzt werden). Wenn mehr als n Jobs vorhanden sind, werden die Jobs in der Warteschlange gespeichert, bis ein Verarbeitungsthread verfügbar ist.

    %Vor%

    Wie gesagt, das ist viel komplizierter zu realisieren, da ich noch immer keine Probleme wie

    berührt habe
    • Stoppen der Worker-Threads
    • Achten Sie darauf, Ausnahmen zu behandeln und dann zur Verarbeitung zurückzukehren
    • usw.

Dies sind nur grundlegende (aber sehr leistungsfähige) Werkzeuge in einer Multi-Threading-Umgebung. Wenn Sie erweiterte Tools benötigen, können Sie die Guava-Bibliothek testen, zum Beispiel mit dem wunderbaren Konzept eines ListenableFuture (die Sie verwenden sollten, wenn Sie das Ergebnis eines Arbeitsthreads benötigen).

Sie hätten dann ein eher einfaches Design, von dem Sie einige ausgeklügeltere Verarbeitungsschritte hinzufügen können, wie bereits in Ihren Kommentaren erwähnt. Es wurde auch darauf hingewiesen, dass es sich dann in einer ziemlich breiten Frage dreht;)

    
Stephan 11.12.2012, 21:19
quelle
0

Zunächst sollten Sie überlegen, wie wichtig die Leistung in dieser Anwendung ist und welche Art von Datenverkehr Sie verarbeiten müssen. Wenn es Ihnen nicht sehr wichtig ist, eine Latenzzeit von 0,1 ms zu jeder Anfrage hinzuzufügen (was meiner Meinung nach nicht der Fall ist, wenn Sie sagen, dass jede Anfrage mehrere Sekunden dauert), ist das Erstellen eines neuen Threads keine merkbaren Kosten. Beachten Sie, dass Ihre Threads ihr Leben beenden sollten, nachdem sie mit ihrer Arbeit fertig sind. Sie werden also nicht Hunderttausende von Threads gleichzeitig haben - sie werden im Laufe der Zeit gestartet und beendet. Wenn Sie "ein paar hunderttausend" Anfragen pro Tag erhalten, sind dies nur mehrere Anfragen pro Sekunde (vorausgesetzt, sie sind gleichmäßig verteilt). Mit solchen Parametern liegt Ihre durchschnittliche Anzahl an aktiven Anfragen in der Größenordnung von einigen Dutzend (etwa 10 pro Sekunde mal mehrere Sekunden pro Anfrage ~ = ein paar Dutzend Anfragen sind zu jedem Zeitpunkt live). Dies ist mehr als die Anzahl der Cores auf Ihrem Computer, sollte aber ohne Probleme gehandhabt werden - wenn diese Threads mit der DB kommunizieren, werden sie die meiste Zeit damit verbringen, auf die Kommunikationsverbindung zu warten. Obwohl ein separater Thread für jede Anfrage möglicherweise nicht das beste Design im Allgemeinen ist, wird es wahrscheinlich einfacher zu implementieren sein als etwas Phantasievolles, wenn man etwas über Futures und Executors lernt.

Beide Lösungen haben also ihre Vorzüge - Futures für besseres Design und möglicherweise bessere Ressourcennutzung (obwohl das von Ihrer Planung abhängen kann) und Thread pro Anfrage, um etwas schnell zu machen (und leicht verstehen zu können, was los ist) auf dem System). Wenn Sie jetzt nur Nebenläufigkeit lernen, würde ich Ihnen empfehlen, es zuerst auf die weniger elegante Art zu machen, um zu verstehen, was das System hinter den Kulissen tun muss. Wenn Sie dann mit diesem "manuellen" Planungsansatz vertraut sind, können Sie auf die höhere Abstraktionsebene gehen, Futures et al. Lernen und Ihren Code umgestalten. Diese zweite Version wird wahrscheinlich viel besser sein als der Code, den Sie schreiben können, wenn Sie sofort mit Futures beginnen.

    
Michał Kosmulski 11.12.2012 21:14
quelle

Tags und Links