Threads in Abhängigkeit voneinander laufen lassen

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

Es gibt 21 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Threads in Abhängigkeit voneinander laufen lassen

    Hallo zusammen,

    im Moment schreibe ich an einem Programm, dass RestRequests in Endlosschleife durchführt (mit Restsharp) und anhand der Response weiteren Code ausführt.
    Damit das ein bisschen schneller vonstattengeht rufe ich im Endeffekt 2 mal die gleiche Funktion über 2 Threads auf:

    VB.NET-Quellcode

    1. For i As Integer = 0 To 1
    2. Dim thread As Thread = New Thread(Async Sub(t)
    3. Do While condition = True
    4. Await Methodexyz()
    5. Loop
    6. End Sub) With {
    7. .IsBackground = True,
    8. .Name = "thread" + CStr(i)
    9. }
    10. threadlist.Add(thread)
    11. Next
    12. For Each t As Thread In threadlist
    13. t.Start()
    14. Next


    Bisher hat es mich nicht gestört dass die beiden Threads sich in die Quere kommen, jedoch habe ich den Code erweitert und nun müsste ich an manchen Stellen
    jeweils auf den anderen Thread warten.

    Ist das prinzipiell möglich?
    @nicerdicer Frag mal Frau Google nach msdn threads synchronisieren.
    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!
    @nicerdicer Häng ggf. noch "Beispiele" an.
    Und:
    Zitiere nicht komplette Posts über den Deinen.
    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 find das auch problematisch zu googeln, ich glaub, es gibt 10 vershciedene Vorgehensweisen, wie man Threads synchronisieren kann, und ausserdem kann man auch ncoh dreierlei darunter verstehen, was das eiglich sein soll.

    Ich täte mal Paralel.For() in den Raum werfen als einen Ansatz, und Async/Await als anderen.
    allerdings beide Ansätze schüttel ich nicht so aussm Ärmel.
    Ich weiss aber, man sollte sie nicht vermischen, also @TE: Welchen Ansatz möchtest du verfolgen?
    @ErfinderDesRades

    Nach kurzer Recherche (wilder Tobak diese Threadsynchronisation) hätte ich eigentlich gedacht dass das Stichwort "Barrier" für mich am geeignetsten wäre.
    Konnte mir aber anhand der Codebeispiele erst einmal keinen Reim darauf machen.

    Um es eventuell noch kurz auszuführen:

    Bei jedem Durchlauf der Wert eines NumericUpDowns geändert, abhängig vom letzten Wert, z.B.:

    Startwert 1000 (Numericupdown1.Value)

    VB.NET-Quellcode

    1. Numericupdown1.Value = NumericUpdown1.Value + Numericupdown1.Value * (1/100) 'Erhöhung um 1%


    Ohne Multithreading bekomme ich hier wie zu erwarten folgende Werte:

    Durchlauf 1: 1010
    Durchlauf 2: 1020,1
    Durchlauf 3: 1030,301
    ....

    Mit Multithreading passiert teilweise folgendes:
    Durchlauf 1: 1010
    Durchlauf 2: 1020,1
    Durchlauf 3: 1020,1
    Durchlauf 4: 1030,301
    ....

    Dadurch bekomme ich unvorhergesehene Werte in meinem Numericupdown die ich nicht möchte.

    Welcher der Ansätze wäre deiner Meinung nach am besten dafür geeignet?
    NumericUpdown ist ein Control, Controls sind für Threading generell nicht geeignet.

    nicerdicer schrieb:

    Bei jedem Durchlauf der Wert eines NumericUpDowns geändert, abhängig vom letzten Wert
    Jo, das bedeutet ebenfalls: Threading ist nicht geeignet.

    Bei Threading muss man mehrere Startwerte haben, und erhält mehrere Ergebnisse.
    Soll das Ergebnis des einen Threads Startwert des nächsten Threads sein, isses Unfug, weil die beiden Threads können ja nicht paralell laufen, sondern nur nacheinander.
    Eine Frage hätte ich noch, ich habe immer noch die Hoffnung dass ich mich irgendwie mit Variablen durchmogeln kann,
    durch welche einer der Threads warten muss.
    Leider ist nach 2 Durchgängen der Threadname nicht mehr korrekt (Nothing anstatt "thread0" bzw. "thread1").

    Im Grund laufen doch die gleichen 2 Threads solange bis die Stop-Bedingung erreicht ist oder nicht?
    Vermutlich habe ich aber eher etwas nicht verstanden...
    @nicerdicer Was genau willst Du eigentlich erreichen?
    Was ist Dein Plan?
    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!
    @RodFromGermany

    Wie schon bei der Threaderstellung erwähnt sende ich in Dauerschleife Requests an eine Website und je nachdem was ich zurückbekomme mache ich dann verschiedenste Dinge.
    Wie ErfinderdesRades schon gesagt hat ist Multithreading ja hierfür nicht geeignet, dachte aber ich kann die Requests zumindest etwas zeitversetzt laufen lassen,
    um einen kleinen Geschwindigkeitsboost zu bekommen.

    Mit mehreren Threads schaffe ich ~ doppelt so viele Requests als mit einem Thread.

    Edit(Dateianhang):
    Bilder
    • IMG-0007.JPG

      507,39 kB, 1.668×2.157, 12 mal angesehen

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

    @nicerdicer verwende bitte gefälligst die Dateianhang-Funktionalität des Forums:
    Erweiterte Antwort => Dateianhänge => Hochladen.
    Du kannst die permanente Abfrage in einem einzelnen Thread laufen lassen.
    Starte dort die neue Abfrage, wenn die alte fertig ist ggf. mit einer kleinen Pause.
    Invoke die Anzeige in den GUI-Thread.
    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!
    Moin @nicerdicer
    ich bin mir nicht sicher, ob wir dir hier helfen können, solange wir nicht wissen, was du eigentlich vorhast. Deine bisherige Schilderung ist zu vage für eine Aussage zu einem so komplexen Themengebiet. Beruflich entwickel ich Restful APIs und Schnittstellen jeder Art auch für Highperformance-Anwendungen und ein solches Problem hatte ich bisher noch nie. Daher vermute ich hier ein Architekturproblem und hier wird es ohne Code und Anwendungsfall schwierig Hilfestellungen zu liefern oder überhaupt erstmal das Problem zu erkennen.


    Ein Computer wird das tun, was du programmierst - nicht das, was du willst.
    Mal angenommen du willst Daten im JSON Format über eine Restful-API
    laden (natürlich alles nur geraten, weil keine konkreten Angaben), dann
    ist die schnellste Variante die ich kenne folgende:

    VB.NET-Quellcode

    1. Public Function GetObject() As T
    2. Dim BaseAddress As String = "Adresse\der\API\"
    3. Dim GetAddress As String = "Pfad\zum\Controller"
    4. Dim Client As HttpClient = New HttpClient With
    5. {
    6. .Timeout = New TimeSpan(2, 0, 0),
    7. .BaseAddress = New Uri(BaseAddress)
    8. }
    9. Client.DefaultRequestHeaders.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json"))
    10. Return Client.GetFromJsonAsync(Of T)(GetAddress).GetAwaiter().GetResult()
    11. End Function


    Ist jetzt nur ein Beispiel, aber hier sparst du dir über die GetAwaiter()-Funktion das ganze For Each-Gedöns mit den Threads.

    Wenn du tatsächlich mit JSON arbeitest dann brauchst du für den Code unter .NET Framework das NuGet-Paket System.Net.Http.Json um die .NET Core Bibliotheken im .Net Framework nutzen zu können. Das nur als Hinweis.

    Auf deinen Fall übertragen kannst du deinen gesamten Code oben ersetzen mit folgender Zeile:

    VB.NET-Quellcode

    1. Methodexyz().GetAwaiter().GetResult()


    Vorausgesetzt Methodexyz ist eine function und kein Sub. Bei asynchronen Subs läuft das etwas anders. So kannst du asynchrone Funktionen sehr einfach synchronisieren. Wenn du das im Background ausführen möchtest kannst du den Aufruf natürlich auch in einen separaten Thread auslagern.

    Also quasi:

    VB.NET-Quellcode

    1. Dim condition As Boolean = True
    2. Task.Factory.StartNew(Sub()
    3. Do While condition
    4. condition = Methodexyz().GetAwaiter().GetResult()
    5. Loop
    6. End Sub)


    Ein Computer wird das tun, was du programmierst - nicht das, was du willst.
    @Yanbel

    Ja alles erfolgt im JSON-Format, ich weiß nicht ob das Projekt unter "illegale Themen" fällt,
    daher versuche ich den Code mal neutral zu posten:

    Nochmal der Funktionsaufruf:

    Mit Multithreading:

    VB.NET-Quellcode

    1. For i As Integer = 0 To 1
    2. Dim thread As Thread = New Thread(Async Sub(t)
    3. Do While autostart= True
    4. Await DoStuff()
    5. Loop
    6. End Sub) With {
    7. .IsBackground = True,
    8. .Name = "thread" + CStr(i)
    9. }
    10. threadlist.Add(thread)
    11. Next
    12. For Each t As Thread In threadlist
    13. t.Start()
    14. Next


    Ohne Multithreading:

    VB.NET-Quellcode

    1. Do While autostart= True
    2. Await DoStuff()
    3. Loop



    Dann hier die Funktion die aufgerufen wird:

    VB.NET-Quellcode

    1. Private Async Function DoStuff() As Task
    2. Dim token As String = "token"
    3. Dim url As String = "url"
    4. Dim request = New RestRequest(Method.POST)
    5. Dim client = New RestClient(url)
    6. Dim payload As Payload = New Payload()
    7. payload.operationName = "OperationName"
    8. 'Set payload variables
    9. payload.variables = New jsonstruct()
    10. payload.variables.variable1 = "1"
    11. payload.variables.variable2 = "2"
    12. payload.variables.variable3 = "3"
    13. payload.query = "<Query>"
    14. request.AddHeader("Content-Type", "application/json")
    15. request.AddHeader("x-access-token", token)
    16. request.AddParameter("application/json", JsonConvert.SerializeObject(payload), ParameterType.RequestBody)
    17. Dim restResponse = Await client.ExecuteAsync(request)
    18. Dim response As Data = JsonConvert.DeserializeObject(Of Data)(restResponse.Content, New JsonSerializerSettings With {
    19. .[Error] = Sub(ByVal sender As Object, ByVal args As ErrorEventArgs)
    20. EditStatus("Bad response from server")
    21. args.ErrorContext.Handled = True
    22. End Sub
    23. })
    24. If restResponse.StatusCode = HttpStatusCode.OK Then
    25. If response.errors Is Nothing Then
    26. If response.data.stuff IsNot Nothing Then
    27. If response.data.stuff.variablexyz = True Then
    28. 'Hier überschneidet sich der Wert mit Multithreading (logischerweise)
    29. globalevariable = globalevariable + globalevariable * (1/100)
    30. End if
    31. Else
    32. EditStatus("No response data")
    33. End If
    34. Else
    35. EditStatus(response.errors(0).message & " (" + response.errors(0).errorType & ")")
    36. End If
    37. Else
    38. EditStatus("Operation failed, try again. (Code:" & restResponse.StatusCode & ")")
    39. End If
    40. End Function


    PS: Entschudligt die Formatierung..
    @nicerdicer Ich würde es so umsetzen. Zwei parallele Threads sind an dieser Stelle nicht ratsam

    VB.NET-Quellcode

    1. Private IsCanceled As Boolean = False
    2. Private Property ResultList As List(Of Double)
    3. Private Async Function DoStuff(Value As Double) As Task(Of Nullable(Of Double))
    4. Dim token As String = "token"
    5. Dim url As String = "url"
    6. Dim request = New RestRequest(Method.POST)
    7. Dim client = New RestClient(url)
    8. Dim payload As Payload = New Payload With {.operationName = "OperationName"}
    9. 'Set payload variables
    10. payload.variables = New jsonstruct()
    11. payload.variables.variable1 = "1"
    12. payload.variables.variable2 = "2"
    13. payload.variables.variable3 = "3"
    14. payload.query = "<Query>"
    15. request.AddHeader("Content-Type", "application/json")
    16. request.AddHeader("x-access-token", token)
    17. request.AddParameter("application/json", JsonConvert.SerializeObject(payload), ParameterType.RequestBody)
    18. Dim restResponse = Await client.ExecuteAsync(request)
    19. Dim response As Data = JsonConvert.DeserializeObject(Of Data)(restResponse.Content, New JsonSerializerSettings With
    20. {
    21. .[Error] = Sub(ByVal sender As Object, ByVal args As ErrorEventArgs)
    22. EditStatus("Bad response from server")
    23. args.ErrorContext.Handled = True
    24. End Sub
    25. })
    26. If restResponse.StatusCode = HttpStatusCode.OK AndAlso response.errors Is Nothing AndAlso response.data.stuff IsNot Nothing AndAlso response.data.stuff.variablexyz Then
    27. Value *= 1.01
    28. Return Value
    29. ElseIf restResponse.StatusCode <> HttpStatusCode.OK Then
    30. EditStatus("Operation failed, try again. (Code:" & restResponse.StatusCode & ")")
    31. ElseIf response.errors IsNot Nothing Then
    32. EditStatus(String.Concat(response.errors.FirstOrDefault().message, " (", response.errors.FirstOrDefault().errorType, ")"))
    33. ElseIf response.data.stuff Is Nothing Then
    34. EditStatus("No response data")
    35. End If
    36. Return Nothing
    37. End Function
    38. Private Sub StartThread()
    39. Dim NewThread As New Threading.Thread With {.IsBackground = True, .Name = "MyBackgroundthread"}
    40. Dim StartValue As Double = 1000
    41. ResultList = New List(Of Double) From {StartValue}
    42. NewThread = Sub()
    43. Do While Not IsCanceled
    44. Dim result As Nullable(Of Double) = DoStuff(ResultList.LastOfDefault()).GetAwaiter().GetResult()
    45. If result IsNot Nothing Then
    46. ResultList.Add(result)
    47. End If
    48. Loop
    49. End Sub
    50. NewThread.Start()
    51. End Sub



    Ein Computer wird das tun, was du programmierst - nicht das, was du willst.