Schleife läuft nicht richtig: verschiedene Durchlaufzeiten und Problem mit anderen Events

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

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

    Schleife läuft nicht richtig: verschiedene Durchlaufzeiten und Problem mit anderen Events

    Hallo liebes Forum,

    ich war vorhin an einem anderen Projekt zugange und habe etwas festgestellt. Aber von vorne:
    Ich hab 'ne Form, zwei Buttons und einen Timer.

    In der Sub von Button_Start gibt es meine While-Schleife. Diese wird nur abgebrochen, wenn Button_Stopp gedrückt wird, weil der den Boolean Abbruch auf true setzt.
    In der While-Schleife befindet sich ein If, dessen Bedingung nur True wird, wenn der Timer feuert (alle 40 ms). Also wenn der nicht kommt, läuft die While-Schleife vor sich hin. Die Sache ist, in meinem If befindet sich Code, der genau getimet sein muss. Es geht um Videobearbeitung. Ich brauche mindestens ein Application.DoEvents(); mit einem zweiten läuft wiederum alles sehr unruhig (das sehe ich an den Diagnosetools). Wenn gar kein Application.DoEvents da ist, hört das Programm nicht mehr auf Button_Stop (App hängt), sogar schlimmer, Run wird nicht mehr auf True gesetzt . Als wenn der Timer nicht mehr durchkommt. X/

    Wie bekomme ich diesen Aufbau sauberer hin? Die Stopwatch meldet alles von 39 Millisekunden bis 50. Aber nie konstant 40 (naja, wenn es 45 wären....)

    Wie gesagt, ich habe ein extra Testprojekt erstellt, füge ich hinzu. Damit's nachstellbar ist.

    Danke und einen schönen Abend

    VB.NET-Quellcode

    1. 'Option Strict On wurde in den Projekteigenschaften festgelegt!
    2. Public NotInheritable Class Form1
    3. Private Run As Boolean = False
    4. Private Abbruch As Boolean = False
    5. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    6. Me.KeyPreview = True
    7. End Sub
    8. Private Sub Button_Start_Click(sender As Object, e As EventArgs) Handles Button_Start.Click
    9. Timer1.Enabled = True
    10. Application.DoEvents()
    11. Dim stopWatch As New Stopwatch()
    12. While Not Abbruch 'solange nicht Stopp gedrückt wurde...
    13. stopWatch.Start()
    14. If Run Then 'und wenn der Timer gerade feuert...
    15. 'tu etwas!
    16. stopWatch.Stop()
    17. TextBox1.Text = stopWatch.ElapsedMilliseconds.ToString
    18. stopWatch.Reset()
    19. 'Application.DoEvents()
    20. Run = False
    21. End If
    22. Application.DoEvents() 'wenn auskommentiert, hört er nicht mehr auf den Button_Stopp und setzt Run nicht auf True
    23. End While
    24. TextBox1.Text = "gestoppt"
    25. End Sub
    26. Private Sub Button_Stopp_Click(sender As Object, e As EventArgs) Handles Button_Stopp.Click
    27. Timer1.Enabled = False
    28. Run = False
    29. Abbruch = True
    30. End Sub
    31. Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
    32. Run = True
    33. End Sub
    34. Private Sub Form1_KeyDown(sender As Object, e As KeyEventArgs) Handles MyBase.KeyDown
    35. If e.KeyCode = Keys.Escape Then
    36. Button_Stopp_Click(0, Nothing)
    37. End If
    38. End Sub
    39. End Class
    Bilder
    • einfaches Form - Kopie.jpg

      17,82 kB, 244×266, 63 mal angesehen
    Sieht alles bissl unnötig kompliziert aus. Was ist denn das eigentlich Ziel?
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen
    @mrMo Ziel ist, dass ein Video aufgenommen wird. Vor der Whileschleife ist eine VideoFileWriter.Open()-Geschichte und hinter der Schleife wird geschlossen. In dem besagten If schreibt der VideoFileWriter einen Frame. Daher muss alles in diesem Sub sein (denke ich...).
    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.
    Mach das Zeugsl von While bis End While mal testweise in ner nebenläufigen Sub, Stichwort Async/Await. Ok, das mit der TextBox geht da nicht, aber wohl der Rest. Dann kannst Du auch problemlos den Button zum Stoppen verwenden.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Aha... warum postest du dann nicht deinen tatsächlichen Code? Damit liese es sich doch viel besser arbeiten.

    Ich täte statt der Schleife und dem Application DoEvents mit Async/Await arbeiten. Schau dir das Thema mal an.
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen
    @Bartosz Windows ist nun mal kein Echtzeitsystem, da wirst Du immer Probleme haben.
    Wenn Du eine genaue Zeitbasis brauchst, kannst Du Dir mal den MultiMedia-Timer ansehen.
    Effizienter Timer mit hoher Auflösung?
    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!
    @mrMo Keine Sorge ;) ich habe nicht den Videocode gepostet, weil ich von vornherein ein Grundsatzproblem vermutet habe. Ich habe mich gewundert, warum diese einfache Geschichte While-If-Timer nicht gerade läuft. Wie @RodFromGermany beantwortete, ist das ein Windows-Problem. Danke an der Stelle! Ich werde heute Abend das Async testen und Rods Effizenter-Timer testen.
    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.
    @VaporiZed Ähm, das klappt nicht. Immer noch Probleme beim Stoppen. Anwenudng reagiert nicht. :(

    VB.NET-Quellcode

    1. Private Sub Button_Start_Click(sender As Object, e As EventArgs) Handles Button_Start.Click
    2. Timer1.Enabled = True
    3. Verarbeitung()
    4. End Sub
    5. Public Async Sub Verarbeitung()
    6. Await Task.Delay(1)
    7. Dim stopWatch As New Stopwatch()
    8. While Not Abbruch 'solange nicht Stopp gedrückt wurde...
    9. stopWatch.Start()
    10. If Run Then 'und wenn der Timer gerade feuert...
    11. 'tu etwas!
    12. 'Application.DoEvents()
    13. Run = False
    14. stopWatch.Stop()
    15. TextBox1.Text = stopWatch.ElapsedMilliseconds.ToString
    16. stopWatch.Reset()
    17. End If
    18. Application.DoEvents() 'wenn auskommentiert, hört er nicht mehr auf den Button_Stopp und setzt Run nicht auf True
    19. End While
    20. TextBox1.Text = "gestoppt"
    21. End Sub



    und wenn ich sowas mache, geht's auch nicht. Also wenn in der Async Sub nur das If ist

    VB.NET-Quellcode

    1. While Not Abbruch
    2. Verarbeitung()
    3. End While
    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.
    versuch mal so anstatt deinem unnötigen Task.Delay

    VB.NET-Quellcode

    1. Private Async Sub Button_Start_Click(sender As Object, e As EventArgs) Handles Button_Start.Click
    2. Timer1.Enabled = True
    3. Await Task.Run(AddressOf Verarbeitung)
    4. End Sub
    Aber Achtung du kannst nicht direkt aus dem separaten Thread auf deine Textbox zugreifen. Dies geht nur per Invoke/BeginInvoke.
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen
    Also, ich glaube nicht, dass Deine Implementierung den Angaben in dem von mir verlinkten Thread entnommen ist. mrMo hat schon wichtiges geschrieben/korrigiert.

    hier mal das vermutlich volle Teil, aber ungetestet:

    VB.NET-Quellcode

    1. Private Async Sub Button_Start_Click(sender As Object, e As EventArgs) Handles Button_Start.Click
    2. Timer1.Enabled = True
    3. Await Task.Run(Sub() Verarbeitung())
    4. TextBox1.Text = "gestoppt"
    5. End Sub
    6. Public Sub Verarbeitung()
    7. Dim stopWatch As New Stopwatch()
    8. While Not Abbruch 'solange nicht Stopp gedrückt wurde...
    9. stopWatch.Start()
    10. If Run Then
    11. Run = False
    12. stopWatch.Stop()
    13. Me.Invoke(Sub() TextBox1.Text = stopWatch.ElapsedMilliseconds.ToString) *
    14. stopWatch.Reset()
    15. End If
    16. End While
    17. End Sub

    * bevor EdR vorbeikommt: gerne auch mal mit BeginInvoke testen, vielleicht merkst Du einen relevanten Unterschied.

    ##########

    …wobei mir die Zeile#10, die ich von Dir übernommen hab, komisch vorkommt. Dieses dauerhafte stopWatch.Start().
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

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

    @VaporiZed
    1.) Dein Code funktioniert im Testprojekt super. Endlich bin ich die Application.DoEvents() los. Mit Timer.Intervall = 500 ms habe ich Ergebnisse von 496-501 ms. Mit Timer.Intervall = 40 ms habe ich Ergebnisse von 47-51 ms. Also irgendwo scheint die Grenze zu sein.
    2.)
    wobei mir die Zeile#10, die ich von Dir übernommen hab, komisch vorkommt. Dieses dauerhafte stopWatch.Start().

    Ich hab mir auch schon gedacht, na, wenn das mal gut ist. Nachher bringt das die Unruhe rein. Aber irgendwie musste ich messen ‍^^
    3.) Im richtigen Videoprojekt läuft alles stabil, solange der Timer über ca. 167 ms (Release, ohne Stopwatch) bis 180 ms (Debugmodus, ohne Stopwatch) bis 200 ms (Debug-Modus, mit Sw) steht. Wenn dieser drunter ist, kommt der VideoFileWriter nicht hinterher. Dachte ich mir auch irgendwie. Aber ohne eure Hilfe hatte auch das nicht sauber funktioniert.
    4.) Die CPU-Auslastung sieht besser aus; nicht mehr so viele. große Peaks.
    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.

    Bartosz schrieb:

    kommt der VideoFileWriter nicht hinterher.
    Schreibst Du auf eine Festplatte?
    Hast Du eine SATA-Festplatte?
    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 Das ist keine SATA mit so nem mechanischem Kopf, sondern schon die SDD oder wie sie heißt. Ist aber ein alter Laptop (mit dem ich immer zufrieden war). Nur ich glaube, langsam, und heutzutage, muss ich mir einen neuen PC kaufen
    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.

    Bartosz schrieb:

    SDD
    Meinte ich, sorry, verwechselt. :whistling:
    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 iwie doppelt und 3-fach gemoppelt.
    Also soweit ich sehe, kann der Timer weg, und die Run-Variable auch.

    VB.NET-Quellcode

    1. Public NotInheritable Class Form1
    2. Private Abbruch As Boolean = False
    3. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    4. Me.KeyPreview = True' das stellt man besser im Designer ein, dann kann diese Sub auch weg
    5. End Sub
    6. Private Async Sub Button_Start_Click(sender As Object, e As EventArgs) Handles Button_Start.Click
    7. Await Task.Run(Sub() Verarbeitung())
    8. TextBox1.Text = "gestoppt"
    9. End Sub
    10. Public Sub Verarbeitung()
    11. Dim stopWatch As New Stopwatch()
    12. While Not Abbruch 'solange nicht Stopp gedrückt wurde...
    13. stopWatch.Start()
    14. Me.BeginInvoke(Sub() TextBox1.Text = stopWatch.ElapsedMilliseconds.ToString) *
    15. stopWatch.Reset()
    16. End While
    17. End Sub
    18. Private Sub Button_Stopp_Click(sender As Object, e As EventArgs) Handles Button_Stopp.Click
    19. Abbruch = True
    20. End Sub
    21. Private Sub Form1_KeyDown(sender As Object, e As KeyEventArgs) Handles MyBase.KeyDown
    22. If e.KeyCode = Keys.Escape Then
    23. Button_Stopp_Click(Nothing, Nothing)
    24. End If
    25. End Sub
    26. End Class
    Im ganzen Code, und auch im ganzen Thread habich nix gefunden, was eigentlich passiert inne Verarbeitung - iwas mit VideoWriter - aber ist nix von zu sehen.