Multi Threading und ProgressBar

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 5 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    Multi Threading und ProgressBar

    Hallo alle Zame,

    ich arbeite gerade an einer Berechnung wo 3D Messpunkte miteinander verglichen werden also immer die X,Y,Z Werte.
    Über eine einfache Vektorrechnung wird der Abstand im Raum ermittelt.

    Ziel ist es die sich jeweils am nächsten liegenden Punkte zu ermitteln den Abstand abzufragen und dem ersten Punkt diesen Abstand zuzuweisen.
    Da wir hier über zwei Punktedateien mit bis zu 16 Millionen Punkten sprechen habe ich das ganze auf mehrere Threads aufgesplittet und lass es
    so auf mehreren Prozessoren gleichzeitig rechnen.

    Das funktioniert auch gut wenn auch noch nicht ganz so schnell wie ich es gern hätte.

    Nun zu meinem Problem.

    Ich würde gern eine Progressbar den Berechnungsfortschritt anzeigen lassen. Nur bekomm ich aus den einzelnen laufenden Threads keine auswertbare Information heraus die ich dazu benutzen könnten den Balken zu füllen.

    Hat das schon mal einer gemacht? Und könnte Mir einen Tip geben?

    Berechnungsroutine des Threads:

    Visual Basic-Quellcode

    1. Public Class Rechnung
    2. Friend PunkteDB1 As List(Of Punkte.Punkt)
    3. Friend PunkteDB2 As List(Of Punkte.Punkt)
    4. Friend Ergebnis As List(Of Punkte.Punkt)
    5. Public Sub Berechnen()
    6. For Each PP1 As Punkte.Punkt In PunkteDB1
    7. Dim Abstand As Double
    8. Dim PP3 As New Punkte.Punkt
    9. For Each PP2 As Punkte.Punkt In PunkteDB2
    10. Dim Wert As Double
    11. Wert = Math.Sqrt((PP2.X - PP1.X) ^ 2 + (PP2.Y - PP1.Y) ^ 2 + (PP2.Z - PP1.Z) ^ 2)
    12. If Wert < Abstand Then
    13. Abstand = Wert
    14. PP3 = PP2
    15. End If
    16. PunkteDB2.Remove(PP3)
    17. Next
    18. If Abstand < 2 Then
    19. PP1.Abstand = Abstand
    20. Ergebnis.Add(PP1)
    21. End If
    22. Next
    23. End Sub
    24. end class



    Aufruf der Threads aus Hauptprogramm in etwa so:

    Visual Basic-Quellcode

    1. Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
    2. Dim Rechner1 As New Rechnung
    3. Dim Rechner2 As New Rechnung
    4. Dim Rechner3 As New Rechnung
    5. Dim Rechner4 As New Rechnung
    6. Dim Einfügen1 As New System.Threading.Thread(AddressOf Rechner1.Berechnen1)
    7. Dim Einfügen2 As New System.Threading.Thread(AddressOf Rechner2.Berechnen2)
    8. Dim Einfügen3 As New System.Threading.Thread(AddressOf Rechner3.Berechnen3)
    9. Dim Einfügen4 As New System.Threading.Thread(AddressOf Rechner4.Berechnen4)
    10. Dim Bereich1 As New List(Of Punkte.Punkt)
    11. Dim Bereich2 As New List(Of Punkte.Punkt)
    12. Dim Bereich3 As New List(Of Punkte.Punkt)
    13. Dim Bereich4 As New List(Of Punkte.Punkt)
    14. Rechner1.PunkteDB1 = Bereich1
    15. Rechner2.PunkteDB1 = Bereich2
    16. Rechner3.PunkteDB1 = Bereich3
    17. Rechner4.PunkteDB1 = Bereich4
    18. Rechner1.PunkteDB2 = PunkteDef2.PunkteDB
    19. Rechner2.PunkteDB2 = PunkteDef2.PunkteDB
    20. Rechner3.PunkteDB2 = PunkteDef2.PunkteDB
    21. Rechner4.PunkteDB2 = PunkteDef2.PunkteDB
    22. Einfügen1.Start()
    23. Einfügen2.Start()
    24. Einfügen3.Start()
    25. Einfügen4.Start()
    26. Einfügen1.Join()
    27. For Each PP As Punkte.Punkt In Rechner1.Ergebnis
    28. Ergebnis.Add(PP)
    29. Next
    30. Einfügen2.Join()
    31. For Each PP As Punkte.Punkt In Rechner2.Ergebnis
    32. Ergebnis.Add(PP)
    33. Next
    34. Einfügen3.Join()
    35. For Each PP As Punkte.Punkt In Rechner3.Ergebnis
    36. Ergebnis.Add(PP)
    37. Next
    38. Einfügen4.Join()
    39. For Each PP As Punkte.Punkt In Rechner4.Ergebnis
    40. Ergebnis.Add(PP)
    41. Next
    42. End Sub
    @tfuchs@cadsys.de Sende vom Thread aus an die Parent-Klasse ein Event, in dessen Parameter Du den entsprechenden Wert übergibst.
    In der empfangenden Klasse musst Du noch invoken, da der Sender in einem anderen Theread läuft.
    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!
    ich würde ganz anders vorgehen - bei so einer grossen Datenmenge, und derart schnellen Einzel-Schritten ist Polling deutlich günstiger, als sich da in jeden Berechnungs-Vorgang einhaken zu wollen.

    Also - evtl. sogar ganz ohne Threading: Mach einen Timer, der alle 300ms abfragt, wie weit der Vorgang inzwischen gediehen ist.
    Eine Aktuallisierung der Anzeige alle 300ms reicht vollkommen - schneller kann eh kein Mensch gucken.
    Also ich hab erstmal die erste Variante ausprobiert von Rod.

    Funktioniert gut und macht genau das was ich wollte. Die Performance hat sich jetzt dadurch auch nicht verschlechtert weil es im Moment ehh. knapp 5 min braucht um alle Punkte zu verrechnen.
    Was ich dazu sagen muss bei der Berechnung läuft eine Doppelschleife da jeder Punkt mit jedem verrechnet wird. Das heißt ich habe jetzt die Aktualisierung in der äußeren Schleife und die läuft,
    laut "StopWatch" bei 600.000 Punkte einmal in 200 ms durch.

    Das heisst je Threat wird einmal alle 200 ms die ProgressBar aktualisiert.

    Ich werde das mit dem Polling auch nochmal probieren, denke aber die finalen Unterschiede sind nicht erkennbar.

    tfuchs@cadsys.de schrieb:

    da jeder Punkt mit jedem verrechnet wird.
    Ich kenne jetzt den Algorithmus nicht, aber mit Parallel.For() könnte da viel zu holen sein: docs.microsoft.com/de-de/dotne…r?view=netframework-4.7.2
    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!