Zähler mit Zeitvorgabe, von x bis y in xxx

  • VB.NET

Es gibt 47 Antworten in diesem Thema. Der letzte Beitrag () ist von wolfi_bayern.

    Es geht um CPU-arme 1,57 Millisekunden.
    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.
    @Yanbel Zähle mal, wie oft Du DateTime.Now aufrufst.
    Überleg Dir mal ne Lösung mit nur einem Aufruf von DateTime.Now in der Prozedur.
    Warum multiplizierst Du mit 1270 um eine Zeile weiter auf >= 1270 zu testen?
    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!
    @VaporiZed: Die CPU-Auslastung bei dieser Methode liegt bei annähernd 2%. Sollte also ausreichen. Da ich die Berechnung mittels Double-Wert aus der Differenz von Date.Now und des initialen DateTime-Values berechne, sollte der Wert den Bedürfnissen entsprechend präzise genug sein, da es ja um ganzzahlige Werte zwischen 0 und 1270 geht, wenn mich nicht alles täuscht.

    @RodFromGermany: Da eine Millisekundenrechnung auf Basis der Ticks des Timers in diesem Fall nicht präzise genug ist (und ich habe mir echt Mühe gegeben) komme ich hier nicht drum herum die Millisekunden-Differenz zwischen der Startzeit und immer der aktuellen Zeit zu berechnen. Ich wüsste nicht wie ich mit einem einzigen Aufruf bei jedem Abgleich die genaue Anzahl an Millisekunden erhalten sollte die seit dem Start vergangen sind. Aus einem Grund, der sich mir noch nicht ganz erschließt, ist die Abweichnung beim Hochzählen einer Variable über die Ticks des Timers viel höher als bei dem Code, den ich gepostet habe. Was die Multiplikation angeht: Ich berechne innerhalb des Timers die verstrichene Zeit. Die Variable Value gibt den aktuellen Wert des Dimmers an. Es handelt sich hier also um eine Umrechnung der Millisekunden unter Berücksichtigung der Laufzeit in Sekunden zu den 1270 Steps des Dimmers.


    Ein Computer wird das tun, was du programmierst - nicht das, was du willst.
    Mag ja sein, dass die CPU-Belastung gut ist. Aber der TE will eine Zeitspanne von ca. 1,57 Millisekunden. Da ein Timer aber nur ganzzahlige Millisekunden als Intervall akzeptiert, sehe ich Deinen Vorschlag nicht als passende Lösung. Es sollen 1270 Schritte in 2 Sekunden absolviert werden. Das sind pro Schritt 1,57 Millisekunden. Wie soll das mit einem Timer gehen, der sich nur entweder jede Millisekunde oder alle 2 ms meldet?
    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.
    Der Timer dient feuert die Abfragen ab die Berechnung der Schritte erfolgt über Double-Werte. Schau dir den Code nochmal in Ruhe an.

    Anbei die Ergebnisse für 3, 5 und 7 Sekunden wie lange der Timer läuft bis der Stop-Punkt erreicht ist. Ich denke die Präzision sollte für das Dimmen einer Birne ausreichend sein.

    EDIT: @RodFromGermany: Hab meinen Code gerade nochmal überflogen und jetzt verstehe ich auch erst was du meinst. Du hast natürlich vollkommen Recht, mit nur einem Abruf des Date.Now (damit hat sich die Abweichung tatsächlich auch fast gänzlich erledigt):

    VB.NET-Quellcode

    1. ...
    2. Dim DN As Date = Date.Now
    3. Dim DateNow As Double = DN.Minute * 60000 + DN.Second * 1000 + DN.Millisecond
    4. ...

    Bilder
    • 3Sekunden.PNG

      1,95 kB, 395×26, 29 mal angesehen
    • 5Sekunden.PNG

      2,07 kB, 423×27, 27 mal angesehen
    • 7Sekunden.PNG

      1,92 kB, 399×22, 23 mal angesehen


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

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

    Lies Dir bitte nochmal die Anforderungen des TE durch. Das mit dem Leuchtmittel war von ihm ein Beispiel, welches aber anscheinend nichts mit dem tatsächlichen Problem zu tun hat:

    kollimann schrieb:

    Lampe wirkt wieder verwirrend......
    andere Erklärung, Bewegung !!!!
    0=ganz unten, 1270 ganz oben, jeder Wert zwischen 0 und 1270 ist quasi "1Punkt höher",
    ich möchte gleichmäßig mit variabler Zeit von Punkt 0 zu 1270

    Das Grundproblem bleibt weiterhin ungeklärt, also ob es tatäschlich um ein praktisches Problem geht, denn:

    VaporiZed schrieb:

    Allerdings wird die Aktion, die nach der Wunsch-1,57ms-Verzögerung liegt, ebenfalls Zeit kosten, möglicherweise viel Zeit. Vielleicht ist es relevant, vielleicht nicht.

    Und nochmal: Es geht nicht um 3 oder 5 oder 7 Millisekunden, sondern um 1,57. Und warum haust Du jetzt eigentlich Sekunden und Millisekunden durcheinander?
    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.

    Yanbel schrieb:

    Umrechnung der Millisekunden unter Berücksichtigung
    Verwende elementare arithmetische Operationen und kürze, was zu kürzen ist. Minimiere die Anzahl der Operationen.
    Und verstehe, was der TE und @VaporiZed gemeint haben.
    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!
    @VaporiZed: Ich verstehen schon was du meinst, aber das was du schreibst haut nicht hin. @kollimann möchte doch in einer bestimmten Zeit (SEKUNDEN) von 0 auf 1270 durchzählen. Die von mir beigefügten Screenshots zeigen nicht die Millisekunden an sondern die Gesamtlaufzeit in der die Schleife durchlaufen wird. Das heißt wenn ich einstelle, dass die Schleife 5 Sekunden durchlaufen soll, dann benötigt mein Programmcode insgesamt 5.001 Millisekunden dafür also ziemlich genau 5 Sekunden (siehe Screenshot). Und wenn du dir meinen Code anschaust, dann wirst du feststellen, dass ich zu keiner Zeit auf die 1,57 MILLISEKUNDEN eingehe, weil mein Code andersherum an das Problem rangeht. Ich durchlaufe NICHT 1270 Steps in der Schleife und halte jedesmal für eine Millisekunde und ein paar zerquetschte an (vor allem halte ich nicht einfach den UI-Thread an!!!) sondern lasse die Schleife für die gewählte Dauer (3, 5, 7 Sekunden als BEISPIEL) durchlaufen. Du kannst das Timer-Interval auch auf 1 setzen, dann werden die Daten im Millisekundentakt an die Update_Wert-Methode gefeuert. Bei welchem Wert du dich gerade befindest zeigt dir dann diese Zeile:

    VB.NET-Quellcode

    1. Dim Value = NewValue / (1000 * Seconds) * 1270


    Und wenn du ganzzahlige Werte braucht, dann setz ein Math.Round außenrum. Ist alles immer noch schneller und präziser als jedesmal den Thread anzuhalten (wie bereits vorgeschlagen). Und wie @petaod bereits geschrieben hat: Windows ist nicht Realtime-fähig, wenn die Schleife also auf die Mikrosekunden genau 5 Skunden lang laufen soll, dann anderes Betriebsystem und nicht .NET.

    @RodFromGermany: Jop, wie in meinem Post davor beschrieben, hast du absolut Recht. Hab den Code schon im vorangegangenen Post korrigiert. :)


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

    Yanbel schrieb:

    Die von mir beigefügten Screenshots zeigen nicht die Millisekunden an sondern die Gesamtlaufzeit in der die Schleife durchlaufen wird.
    Ok, da habe ich mich durch die Angaben verwirren lassen, da 3.001 ms für mich nicht 3001 ms sind, sondern ich das als us-amerikanische Variante von 3,001 ms gesehen habe. Den Tausender-Trennpunkt der deutschen Schreibweise sehe ich zu selten. Auch haben mich die 24,41 S verwirrt, da dachte ich an eine Gesamtlaufzeit von ebensovielen Sekunden. Dann ist das geklärt. Nun kannst Du mir bestimmt sagen, wie man das Ziel erreichen kann, nach jedem der 1270 (oder sind es eigentlich doch 1271?) Schritt eine Aktion ausführen zu lassen. Denn darum geht es ja dem TE.
    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.
    @VaporiZed Ja, hab halt anders herum gedacht. Deine Werte kannst du in der Update_Wert-Methode abfragen. Wenn du sicher gehen willst, dass du wirklich keinen Wert auslässt dann füg in der Update_Wert-Methode noch folgenden Code ein:

    VB.NET-Quellcode

    1. Task.Factory.StartNew(Sub()
    2. Dim y As Integer = Math.Truncate(Value)
    3. For i = LetzterWert To y - 1
    4. Console.WriteLine(i)
    5. Next
    6. LetzterWert = y
    7. End Sub)


    Console.WriteLine ist dann natürlich der Platzhalter für deinen Code und LetzterWert ist ein Integer Wert, der außerhalb der Methode deklariert wird.

    EDIT: Ich habe es jetzt nochmal getestet mit dem Hochzählen und dem Durchlaufen der Schleife von 0 - 1270 unter annähernder Berücksichtung der Nachkommastellen der Millisekunden:

    VB.NET-Quellcode

    1. Private Sub Alternate(Seconds As Integer)
    2. Dim y As Double = (Seconds * 1000) / 1270
    3. Dim x As Double = y Mod Math.Truncate(y)
    4. Dim Zusatzkosten As Double = 0
    5. y = Math.Truncate(y)
    6. For i = 0 To 1270
    7. Zusatzkosten += x
    8. If Zusatzkosten >= 1 Then
    9. Zusatzkosten -= 1
    10. Threading.Thread.Sleep(y + 1)
    11. Else
    12. Threading.Thread.Sleep(y)
    13. End If
    14. Next
    15. End Sub


    Hier die Ergbnisse für die Gesamtlaufzeit von 3, 5, 7 Sekunden.
    Bilder
    • 3SekundenNew.PNG

      1,88 kB, 437×18, 17 mal angesehen
    • 5SekundenNew.PNG

      1,94 kB, 437×18, 20 mal angesehen
    • 7SekundenNew.PNG

      1,95 kB, 432×20, 21 mal angesehen


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

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Yanbel“ ()

    Ich glaub ich geb auf. 1. Ist es nicht mein Thread, 2. kann ich Dir nicht mehr folgen. Threading.Thread.Sleep war schon nach Post#2 raus. Meine Werte sind's nicht, da das nicht mein Thread ist, aber das ist Haarspalterei. Und Werte will der TE auch nicht abfragen, sondern er will Code nach jedem der 1270 bzw. 1271 Schritte ausführen. Also: Zähle bis 1270, führe nach jedem einzelnen Schritt den Code XYZ aus und nach allen 1270 Schritten soll der Vorgang ca. 2 Sekunden gedauert haben, wobei die Ausführung der 1270 Aufrufe von XYZ in konstant gleichen Abständen geschehen soll, ohne dabei die CPU zu belastenDa ich entweder den roten Faden zu Deiner Lösung verloren habe oder alternativ dieser nicht existiert, um dem Problem des TE zu begegnen, bin ich raus.
    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.
    Die Gesamtlaufzeit passt, alle 1270 Einzelsteps werden erreicht und nach jedem Step kann Code ausgeführt werden und die CPU wird auch nicht belastet. Welche Anforderung wird deiner Meinung nach nicht erfüllt?
    Wie hast du dir denn das For i = 0 to 1270-Gedöns vorgestellt, wenn nicht mit Threading.Thread.Sleep? Wie genau hattest du vor dem Programm beizubringen, dass es eine For-Schleife in einer bestimmten Zeit durchlaufen soll?

    Hier nochmal etwas schöner:

    @kollimann: Du legst dir die folgende Klasse an:

    Klasse

    VB.NET-Quellcode

    1. Public Class Recheneinheit
    2. Public Property Identifier As Guid
    3. Public Property Milliseconds As Integer
    4. Public Property InitialMS As Integer
    5. Public Property AciveMS As Integer
    6. Public Property Value As Integer
    7. Private LastValue As Integer
    8. Public Event NextStep(Identifier As Guid, xStep As Integer, Milliseconds As Integer)
    9. Public WithEvents IntervalTimer As New Timer
    10. Public Sub Start()
    11. Dim DN As Date = Date.Now
    12. InitialMS = DN.Minute * 60000 + DN.Second * 1000 + DN.Millisecond
    13. LastValue = 0
    14. IntervalTimer.Interval = 1
    15. IntervalTimer.Start()
    16. End Sub
    17. Public Sub Timer_Tick(sender As Object, e As EventArgs) Handles IntervalTimer.Tick
    18. Dim DN As Date = Date.Now
    19. AciveMS = DN.Minute * 60000 + DN.Second * 1000 + DN.Millisecond
    20. Zählen(AciveMS - InitialMS)
    21. End Sub
    22. Private Sub Zählen(NewValue As Integer)
    23. Value = NewValue / Milliseconds * 1270
    24. Task.Factory.StartNew(Sub()
    25. Dim y As Integer = Math.Truncate(Value)
    26. For i = LastValue To y - 1
    27. If i < 1270 Then
    28. RaiseEvent NextStep(Identifier, i, Milliseconds)
    29. Else
    30. RaiseEvent NextStep(Identifier, 1270, Milliseconds)
    31. Exit Sub
    32. End If
    33. Next
    34. LastValue = y
    35. End Sub)
    36. If Value >= 1270 Then
    37. IntervalTimer.Stop()
    38. End If
    39. End Sub
    40. Public Sub New()
    41. Identifier = Guid.NewGuid
    42. End Sub
    43. End Class


    Und dann initialisierst du die Klasse um den Timer zu starten:

    Initialisierung

    VB.NET-Quellcode

    1. Private Sub Start_Click(sender As Object, e As EventArgs) Handles bnStart.Click
    2. Dim Zähler1 As New Recheneinheit
    3. Zähler1.Milliseconds = 1000
    4. AddHandler Zähler1.NextStep, AddressOf NextStep
    5. Zähler1.Start()
    6. End Sub


    Und die Methode um das NextStepEvent abzufangen:

    EinzelschritteAbfangen

    VB.NET-Quellcode

    1. Private Sub NextStep(Identifier As Guid, NextStep As Integer, Milliseconds As Integer)
    2. 'Hier implementierst du den Code, den du bei jedem Step ausführen willst
    3. End Sub



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

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

    OK, erstmal versuche ich den Sinn hinter dem ganzen zu erklären, da diese Frage ja öfter auftaucht, es sollte auch niemals ein Geheimnis sein, ich wollte nur Verwirrung vermeiden !
    Meine Beispiele mit Bewegung oder Helligkeit waren nicht aus der Luft gegriffen, das Programm ist eine Lichtsteuerung.
    Mein Programm sendet Werte für Bewegung und Helligkeit an das "Master" Licht-Programm. Ich könnte alles manuell per Regler steuern, aber das soll mir meine Software ja abnehmen. Regler per Hand am Lichtpult von ganz unten nach ganz oben im Takt der Musik würde ergeben Lampe von ganz unten nach ganz oben....das soll mein Programm an den "Master" senden, da hab ich die Hände frei.
    Also Grundlegend geht es um BPM welche in Zeit umgerechnet wird und daraus ergibt sich halt dieses 1270 Schritte in xxx Zeit/quasi pro BPM/Takt.
    Daher ist es auch völlig wurst wie genau mein Programm (Genauigkeit pro Durchlauf in Sekunden) arbeitet, wenn es zu "langsam" ist wird der Wert geändert das es schneller geht....eben darum nützt mir eine Version die im 1 Sekunden Abstand arbeitet nichts und irgendwie muss ich ja die BPM/den Takt in Zeit umrechnen, sonst versteht der PC ja garnichts.
    Mit meinem Beispiel wollte ich nur aufzeigen das eben der Intervall bei einem Durchlauf in 2 Sekunden eben rechnerich 1,57ms Intervall bedeutet. Das ändert sich wenn ich 1,5Sekunden Durchlauf möchte natürlich immer, es war nur ein Beispiel.
    Ich hoffe erstmal jetzt Klarheit geschaffen zu haben was wieso warum.

    Das Beispiel von @Yanbel kann ich nicht testen, da gibts eine Fehlermeldung, hab Copy/Paste gemacht, in der Klasse die ich erstellen sollte wird Task bemängelt...Task wurde nicht deklariert.....das Thema Klassen ist Neuland für mich.

    Danke Heiko
    @Yanbel
    Ok, ich hab es hin bekommen das es läuft !
    Ich verstehe aber nicht oder noch nicht was du da "machst".....daher muss ich einige Fragen stellen.
    1. wo änder ich die "Durchlaufzeit" ?
    2. wie rufe ich das mehrfach auf? benötige ich für jedes "zählen" so eine Klasse?
    3. ich benötige für jeden einzelnen Aufruf Optionen,
    1x hochzählen,
    1x runter zählen,
    1x hoch und wieder runter zählen,
    bis manuell stop immer wieder hochzählen,
    bis manuell stop immer wieder runter zählen,
    bis manuell stop hoch runter hoch runter......
    4. wo änder ich die Schrittweite, also die 1270 ?
    um das richtig testen zu können muss ich kapieren was da gemacht wird und wo ich was anpassen/umschreiben muss, ich muss es einfach verstehen...........

    Danke
    Frage 1:
    Die Durchlaufzeit gibst du in Millisekunden an wenn du die Klasse initialisierst:

    VB.NET-Quellcode

    1. Dim Zähler1 As New Recheneinheit
    2. Zähler1.Milliseconds = 1000
    3. AddHandler Zähler1.NextStep, AddressOf NextStep


    Frage 2:
    Ja für jeden Durchlauf eine neue Klasse initialisieren. Kannst also auch für jeden Durchlauf eine andere Zeit definieren.

    Frage 3:
    Alle Aufrufoptionen kannst du in dem Sub NextStep realisieren. Die übergebene Variable NextStep enthält die Zahl zwischen 0-1270. Runterzählen ist bisher nicht vorgesehen. Das müssen wir uns sonst gesondert anschauen.

    Frage 4:
    Meinst du hier, dass du die 1270 umändern willst, also Beispielsweise in 0-1500?


    Ein Computer wird das tun, was du programmierst - nicht das, was du willst.
    @Yanbel
    1 - hatte ich gerade gefunden
    2 - verstehe ich so....z.B. 2 Aufruf--->Dim Zähler2 as New....
    3 - ?
    4 - 1270 sind quasi 100% "Weg", wenn ich nur 50% "Weg" möchte dann müsste ich von 317 - 952 zählen, oder eben "nicht ganz hoch" wäre 0 bis 635, oder ab der Hälfte bis ganz hoch wäre 635 bis 1270......
    zumindest habe ich das so Momentan, wenn man umdenkt kann man das auch in der Auswertung klären, immer von 0-1270 zählen und nur die Werte weiter senden die benötigt werden.
    wobei, wenn man das in der Auswertung macht, dann ändert sich das Timing ja......ich denk mal nach......

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

    2: Korrekt
    3: Wäre gut gewesen die Anforderung vorher zu haben. Ist in diesem Konstrukt schwierig zu realisieren. Weil Hoch- und Runterzählen ja jetzt quasi die doppelte Strecke sind und die Zeit sich damit zwangsläufig auch verdoppelt. Da muss ich in Ruhe mal drüber nachdenken. Melde ich mich später zu.
    4: Ja, kann man eigentilich problemlos umsetzen. Musst halt nur die Anzahl der Steps Variable machen. Also überall wo 1270 steht durch eine Variable ersetzen, die du pro Timer einstellen kannst.


    Ein Computer wird das tun, was du programmierst - nicht das, was du willst.
    @Yanbelnull3. also wenn ich drüber nachdenke ist das irre.....definiere ich es mal neu/anders....wenn hoch/runter DANN nicht hoch/runter in EINEM Durchlauf sondern, EIN Durchlauf hoch der nächste Durchlauf runter der nächste wieder hoch der nächste wieder runter...null
    ja und was ich noch nicht weiß, weil ich nicht verstehe was du da tust, WENN dieses "Konstrukt" im Loop läuft....lässt sich das Timing denn ändern? Wie ich das verstehe starte ich das "Konstrukt" ja mit einem festen Timing?

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