Probleme mit Parallel.For

  • VB.NET
  • .NET (FX) 4.0

Es gibt 30 Antworten in diesem Thema. Der letzte Beitrag () ist von oobdoo.

    @oobdoo Zunächst muss die Schleife, die Du parallelisieren willst, in einer "normalen" For-Schleife funktionieren.
    Packe dazu den Code aus der anonymen Methode in eine "echte" Methode und bring sie zum Laufen.
    Danach stellst Du das auf Parallel.For um.
    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!
    Das hatte ich doch schon seit Post #3 gemacht. Zwei Methoden die beide das gleiche bewirken sollen. Schleifen1 mit den normalen For-Schleifen, was funktioniert, und die Methode Schleifen2 worin meine Versuche stecken die gleiche Wirkweise wie von Schleifen1 zu bekommen.
    Aktuelles Projekt: Z80 Disassembler für Schneider/Amstrad CPC :love:

    oobdoo schrieb:

    Das hatte ich doch schon seit Post #3 gemacht.
    Hast Du nicht:

    VB.NET-Quellcode

    1. Dim result = Parallel.[For](0, 1000, ergebnis1 = TuWas("a", i1))
    In TuWas() müsste dann dies alles drin stecken:

    VB.NET-Quellcode

    1. For i2 = 0 To 1000
    2. ergebnis2 = TuWas("b", i2)
    3. For i3 = 0 To 1000
    4. ergebnis3 = TuWas("c", i3)
    5. ergebnis = Trim(ergebnis1 + ergebnis2 + ergebnis3)
    6. If ergebnis = habenwill Then
    7. tuwasanderes(ergebnis)
    8. Exit Sub
    9. End If
    10. Next
    11. Next
    ############################
    Dein Quellcode müsste so aussehen:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Sub Schleifen2()
    2. Parallel.[For](0, 1000, AddressOf TueNochWas)
    3. End Sub
    4. Sub TueNochWas(i1 As Integer)
    5. ergebnis1 = TuWas("a", i1)
    6. For i2 = 0 To 1000
    7. ergebnis2 = TuWas("b", i2)
    8. For i3 = 0 To 1000
    9. ergebnis3 = TuWas("c", i3)
    10. ergebnis = Trim(ergebnis1 + ergebnis2 + ergebnis3) ' <<<<<<<<<<<<<<<<<<<<
    11. If ergebnis = habenwill Then
    12. tuwasanderes(ergebnis)
    13. Exit Sub
    14. End If
    15. Next
    16. Next
    17. End Sub
    Und wenn ich mir die markierte Zeile ansehe, muss ich Dir sagen, dass Dein Problem so nicht parallelisierbar ist, weil die Umläufe abhängig voneinander sind, die müssen unabhängig voneinander sein. Sorry.

    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!

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

    garnet. Also an den Schleifen kannste nix verbessern.
    Massgeblich in dem Fall ist der Code in der innersten Schleife - ob man da was effizienteres formulieren kann.

    Oder man untersucht die Daten nochmal neu. Oft kann man aus dem Fehlschlag eines Zwischenergebnisses ableiten, dass man den ganzen Weg - mit evtl 1000 weiteren Permutationen - garnet weiterverfolgen muss - Stichwort Backtracking.
    Oder vielleicht sind die Daten iwie in eine ssortierte Ordnung zu bringen - da kann man dann meist auch enorm Effizienz gewinnen.

    Jo, mit deine 3 Schleifen kann man auch Backtracking anwenden:
    Wenn sich in der äussersten schleife schon zeigt, dass der erste Teil von habenwill nicht matcht, dann kann man die inneren schleifen gleich überspringen. Performance-Gewinn von ca 100.000%
    Mit Parallel.For komme ich also nicht weiter. Da dachte ich mir ich versuche es mit Multithreading. Klappt aber auch nicht, weil kein Ereignis durch RaiseEvent ausgelöst wird.

    Anbei der Code. Das gesuchte wird in der 3er Schleife gefunden. Dann soll ein Event erzeugt werden, auf welches ich im Hauptprogramm reagieren kann. Geplant hatte ich, dort den Thread abzubrechen. Aber so weit bin ich gar nicht gekommen, weil eben kein Event ankommt. Wo liegt der (Denk)Fehler?

    Hauptprogramm:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Option Strict On
    2. Imports System
    3. Imports System.Threading
    4. Imports System.Threading.Tasks
    5. Imports System.Text.StringBuilder
    6. Public Class ParallelTest3
    7. Public maxwert As Integer = 20
    8. Public rückgabe As String
    9. Public habenwill As String = "a1 b2 c3"
    10. Public WithEvents m As multi
    11. Public Sub New()
    12. Debug.Flush()
    13. meintask()
    14. End Sub
    15. Public Sub meintask()
    16. Dim mythread As Threading.Thread
    17. Dim m As multi = New multi(maxwert, 1, habenwill)
    18. mythread = New Thread(AddressOf m.schleife)
    19. mythread.Start()
    20. End Sub
    21. Public Sub multidone(obj As Object, result As String) Handles m.done
    22. Dim s As String = result
    23. 'mythread.Abort()
    24. MsgBox(s)
    25. End Sub
    26. End Class


    Unterprogramm:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Option Strict On
    2. Public Class multi
    3. Public maxwert As Integer
    4. Public verzögerung As Integer
    5. Public gesucht As String
    6. Public gefunden As String
    7. Public Event done(obj As Object, gefunden As String)
    8. Public Sub New(m As Integer, v As Integer, g As String)
    9. maxwert = m
    10. verzögerung = v
    11. gesucht = g + " "
    12. End Sub
    13. Public Sub schleife()
    14. Dim ergebnis As String
    15. Dim ergebnis1 As String
    16. Dim ergebnis2 As String
    17. Dim ergebnis3 As String
    18. For i1 = 0 To maxwert
    19. ergebnis1 = TuWas("a", i1)
    20. For i2 = 0 To maxwert
    21. ergebnis2 = TuWas("b", i2)
    22. For i3 = 0 To maxwert
    23. ergebnis3 = TuWas("c", i3)
    24. ergebnis = ergebnis1 + ergebnis2 + ergebnis3
    25. If ergebnis = gesucht Then
    26. gefunden = ergebnis
    27. Debug.WriteLine(ergebnis)
    28. Debug.WriteLine(" gefunden...")
    29. RaiseEvent done(Me, gefunden)
    30. Else
    31. Debug.WriteLine(ergebnis)
    32. End If
    33. 'Threading.Thread.Sleep(verzögerung)
    34. Next
    35. Next
    36. Next
    37. End Sub
    38. Public Function TuWas(s As String, i As Integer) As String
    39. Return s + i.ToString + " "
    40. End Function
    41. End Class
    Aktuelles Projekt: Z80 Disassembler für Schneider/Amstrad CPC :love:
    Jetzt scheint es mit dem Event doch zu klappen. 8o
    Dann kann ich mich morgen darum kümmern wie ich sauber den Thread beenden kann.

    Schonmal Danke an alle die mir bis hierher geholfen haben. :)

    Hauptprogramm
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Option Strict On
    2. Imports System
    3. Imports System.Threading
    4. Imports System.Threading.Tasks
    5. Imports System.Text.StringBuilder
    6. Public Class ParallelTest3
    7. Public mythread As Threading.Thread
    8. Public maxwert As Integer = 20
    9. Public rückgabe As String
    10. Public habenwill As String = "a1 b2 c3"
    11. Public WithEvents m As multi
    12. Public Sub New()
    13. Debug.Flush()
    14. meintask()
    15. End Sub
    16. Public Sub meintask()
    17. m = New multi(maxwert, 1, habenwill)
    18. mythread = New Thread(Sub() m.schleife())
    19. mythread.Start()
    20. End Sub
    21. Public Sub multidone(obj As Object, result As String) Handles m.done
    22. Dim s As String = result
    23. 'mythread.Suspend()
    24. MsgBox(s)
    25. End Sub
    26. End Class


    Unterprogramm
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Option Strict On
    2. Public Class multi
    3. Public maxwert As Integer
    4. Public verzögerung As Integer
    5. Public gesucht As String
    6. Public gefunden As String
    7. Public Event done(obj As Object, gefunden As String)
    8. Public Sub New(m As Integer, v As Integer, g As String)
    9. maxwert = m
    10. verzögerung = v
    11. gesucht = g + " "
    12. End Sub
    13. Public Sub schleife()
    14. Dim ergebnis As String
    15. Dim ergebnis1 As String
    16. Dim ergebnis2 As String
    17. Dim ergebnis3 As String
    18. For i1 = 0 To maxwert
    19. ergebnis1 = TuWas("a", i1)
    20. For i2 = 0 To maxwert
    21. ergebnis2 = TuWas("b", i2)
    22. For i3 = 0 To maxwert
    23. ergebnis3 = TuWas("c", i3)
    24. ergebnis = ergebnis1 + ergebnis2 + ergebnis3
    25. If ergebnis = gesucht Then
    26. gefunden = ergebnis
    27. Debug.WriteLine(ergebnis)
    28. Debug.WriteLine(" gefunden...")
    29. RaiseEvent done(Me, gefunden)
    30. 'Exit Sub
    31. Else
    32. Debug.WriteLine(ergebnis)
    33. End If
    34. 'Threading.Thread.Sleep(verzögerung)
    35. Next
    36. Next
    37. Next
    38. End Sub
    39. Public Function TuWas(s As String, i As Integer) As String
    40. Return s + i.ToString + " "
    41. End Function
    42. End Class
    Aktuelles Projekt: Z80 Disassembler für Schneider/Amstrad CPC :love:

    oobdoo schrieb:

    gesucht = g + " "
    Ist das mit dem Leerzeichen am Ende korrekt?
    In Deinem ergebnis kommt keins vor.

    oobdoo schrieb:

    Geplant hatte ich, dort den Thread abzubrechen.

    oobdoo schrieb:

    Dann kann ich mich morgen darum kümmern wie ich sauber den Thread beenden kann.
    Ein Thread wird abgebrochen, indem die Thread-Prozedur verlassen wird, einfach Return und feddich.
    Das evenmt signalisiert dem Hauptprogramm dann nur noch die Beendigung des Threads.
    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!
    nocheinmal: Du kannst mit Backtrackingg die Performance exorbitant beschleunigen.
    In deim Fall konkret bedeutet das: Prüfe das Teilergebnis Ergebnis1. Wenn das nicht akzeptabel ist, kannste dir die inneren Schleifen komplett sparen.
    Dasselbe gilt für Ergebnis2.
    Threading wirstedann wohl nicht mehr brauchen.
    Doch, Threading wird gebraucht (Kenntnisstand jetzt).

    Meine Anfrage im Forum war allgemein gehalten. Im eigentlichen Projekt sieht es im Code komplizierter aus, daher hatte ich bei der Anfrage ein einfaches Code Beispiel verwendet. Durch eure Antworten hab ich das Thema Threading/Parallel.For besser verstanden. Resultat: Im eigentlichen Projekt mit Threading schneller am Ziel (0.xxx Sekunden) als mit den verschachtelten For/Next Schleifen (>6 Sekunden). Damit kann ich in meinem Projekt weiterarbeiten.
    Aktuelles Projekt: Z80 Disassembler für Schneider/Amstrad CPC :love:

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „oobdoo“ ()