Seite 1 von 2

SetGadgetText und SetGadgetState sehr CPU lastig?

Verfasst: 05.04.2013 13:48
von Micha122
Hallo!
In meinem Programm lese ich aus einer Textdatei Datensätze und und schreibe diese in eine SQL-DB.
Ging selbst bei 300000 Datensätzen recht fix, bis ich auf die Idee kam ein Fortschrittsfenster einzubauen.

Erst nachdem ich die Gadgets nur alle 100 Datensätze aktualisierte war das Ergebnis einigermaßen OK.
Trotz der Verzögerung von "alle 100 Datensätze" ist mir jedoch aufgefallen, das nur die Gadget Befehle 10% der Programmausführungszeit benötigen.

Hier ein kleines Beispiel zum veranschaulichen:

Code: Alles auswählen

anzahl=300000
; Fenster und Gadgets öffnen
  Window_0 = OpenWindow(#PB_Any, 0, 0, 740, 270, "Daten importieren", #PB_Window_SystemMenu | #PB_Window_TitleBar | #PB_Window_ScreenCentered)
  ProgressBar_0 = ProgressBarGadget(#PB_Any, 200, 20, 290, 30, 0, anzahl, #PB_ProgressBar_Smooth)
  Text_0 = TextGadget(#PB_Any, 200, 50, 290, 20, "", #PB_Text_Center)
  Text_1 = TextGadget(#PB_Any, 20, 90, 110, 20, "Vorlaufdaten:", #PB_Text_Right)
  Text_2 = TextGadget(#PB_Any, 10, 120, 120, 25, "Hauptdaten A:", #PB_Text_Right)
  Text_3 = TextGadget(#PB_Any, 20, 150, 110, 20, "Hauptdaten B:", #PB_Text_Right)
  Text_4 = TextGadget(#PB_Any, 20, 180, 110, 20, "Langtexte:", #PB_Text_Right)
  Text_5 = TextGadget(#PB_Any, 140, 90, 220, 20, "")
  Text_6 = TextGadget(#PB_Any, 140, 120, 200, 20, "")
  Text_7 = TextGadget(#PB_Any, 140, 150, 230, 20, "")
  Text_8 = TextGadget(#PB_Any, 140, 180, 230, 20, "")
  Button_0 = ButtonGadget(#PB_Any, 310, 230, 100, 25, "Abbruch")
  WaitWindowEvent() 
  
  ;Code ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  While ee<100000
    a+1
    b+1
    c+1
    ee+1
   ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   
   
   
   
   verzoegerung+1 
   If verzoegerung=20
    ;Gadgets aktualisieren
          SetGadgetText(Text_0,Str(a+b+c)+" von "+Str(anzahl))
          SetGadgetState(ProgressBar_0,a+b+c)
          SetGadgetText(Text_6,Str(a)+" von 100000")
          SetGadgetText(Text_8,Str(b)+" von 100000")
          SetGadgetText(Text_7,Str(c)+" von 100000")
          WaitWindowEvent()
 ;Abbruch Button abfragen
          If EventGadget()=Button_0
            result=MessageRequester("Achtung!","Möchten Sie wirklich abbrechen?",#PB_MessageRequester_YesNo)
            If result=#PB_MessageRequester_Yes          
            End      
          EndIf
        EndIf
        verzoegerung=0
      EndIf
  Wend
Im Beispiel werden die SetGadget Befehle nur alle 20 mal ausgeführt, da sonst sogar dieser simple Code bei mir mehrere Minuten dauert.

Oder mache ich da vielleicht was falsch?? :oops:

Gruß, Michael

Re: SetGadgetText und SetGadgetState sehr CPU lastig?

Verfasst: 05.04.2013 13:56
von NicTheQuick
Wo ist denn hier eine korrekte Eventschleife? Ich sehe nur ein 'WaitWindowEvent()' vor der Schleife. Und innerhalb alle 20 Durchläufe ein 'EventGadget()' ohne Überprüfung auf ein vorher eingehendes '#PB_Event_Gadget'-Event.

Ansonsten ist es aber normal, dass tausende Gadget-Aktualisierungen pro Sekunde alles verlangsamen, weil diese Aktualisierungen wiederum Events erzeugen, die erst abgearbeitet werden müssen. Deswegen macht man das z.B. mit Timern.

Re: SetGadgetText und SetGadgetState sehr CPU lastig?

Verfasst: 05.04.2013 14:08
von Micha122
Wozu eine Eventschleife? Das Fenster dient nur zur Ausgabe, mit Ausnahme des "Abbruch" Button.

Wie funktioniert das mit Timern?

Gruß

Re: SetGadgetText und SetGadgetState sehr CPU lastig?

Verfasst: 05.04.2013 14:16
von STARGÅTE
Also, das Auge kann gerade mal ~24 Einzelbilder pro Sekunde wahrnehmen, es ist also quatsch hier innerhalb weinger Sekunden 10000 änderungen an einem Gadget durchknallen zu lassen.

Ein WaitWindowEvent() hast du ja in deiner schleife unten drin, aber du prüfst dort nicht, welches Event stattfand.
Außerdem heißt WaitWindowEvent() dass er trotzdem eine gewisse Zeit wartet.
Dort könntest du zB nur WindowEvent schreiben.

Ansonsten kannst du mit AddWindowTimer() einen Timer erstellen, der alle 50ms (reicht aus) die Gadgets aktualisiert.
Der Timer wird dann wie andere Events in der Eventschleife abgefragt.

Re: SetGadgetText und SetGadgetState sehr CPU lastig?

Verfasst: 05.04.2013 14:17
von Josh
NicTheQuick hat geschrieben:Ich sehe nur ein 'WaitWindowEvent()' vor der Schleife.
Ich seh sogar zwei WaitWindowEvent() :D

@Micha122
Gewöhne dir saubere Einrückungen an. So wie du deinen Code schreibst, verlierst du schnell den Überblick und einer der dir Hilfe leisten soll, hat wahrscheinlich wenig Bock erst deinen Code ordentlich zu formatieren.

Re: SetGadgetText und SetGadgetState sehr CPU lastig?

Verfasst: 05.04.2013 14:19
von NicTheQuick
Eine Eventschleife braucht man IMMER, wenn man mit Fenstern arbeitet. Weil alles mögliche Events liefert, die nur abgearbeitet werden, wenn man auch '(Wait)WindowEvent()' aufruft. Tut man das nicht, denkt Windows irgendwann, dass das Fenster nicht mehr reagiert und schreibt "(keine Rückmeldung)" in die Titelleiste.
Events kommen schon dann, wenn man nur die Maus über das Fenster bewegt, seine Größe ändern oder es versucht oder Gadgets aktualisiert, wie z.B. bei 'SetGadgetText()'.

Starte den Code, bewege die Maus oder mach sonst irgendwas, und du siehst, was ich meine.

Code: Alles auswählen

Define event.i

If OpenWindow(0, 0, 0, 400, 400, "Eventtest")
	Repeat
		event = WaitWindowEvent()
		Debug "Event: " + event
	Until event = #PB_Event_CloseWindow
EndIf
Edit:
Josh hat geschrieben:
NicTheQuick hat geschrieben:Ich sehe nur ein 'WaitWindowEvent()' vor der Schleife.
Ich seh sogar zwei WaitWindowEvent() :D
Oha, tatsächlich. ^^

Re: SetGadgetText und SetGadgetState sehr CPU lastig?

Verfasst: 05.04.2013 14:31
von Kiffi
hier mal ein Beispiel mit einem Thread und PostEvents:

Code: Alles auswählen

Enumeration #PB_Event_FirstCustomValue
  #EventBeginProcessing
  #EventUpdateStatusbar
  #EventProcessingFinished
EndEnumeration

EnableExplicit

Global ProgressBarValue

Procedure myThread(DummyVar)
  
  Protected  Counter
  
  PostEvent(#EventBeginProcessing)
  
  For Counter = 0 To 100
    ProgressBarValue = Counter
    PostEvent(#EventUpdateStatusbar)
    Delay(100)
  Next
  
  PostEvent(#EventProcessingFinished)
  
EndProcedure

#myWindow=0
#myButton=0
#myProgressbar=1

OpenWindow(#myWindow, #PB_Ignore, #PB_Ignore, 285, 88, "Worker")
ButtonGadget(#myButton, 10, 5, 265, 35, "Starte lang dauernden Prozess")
ProgressBarGadget(#myProgressbar, 10, 50, 265, 20, 0, 100)

Define Thread

Repeat
  
  Select WaitWindowEvent()
      
    Case #PB_Event_Gadget
      
      Select EventGadget()
          
        Case #myButton
          
          Thread = CreateThread(@myThread(), 42)
          
      EndSelect
      
    Case #EventBeginProcessing
      
      DisableGadget(#myButton, #True)
      
    Case #EventUpdateStatusbar
      
      SetGadgetState(#myProgressbar, ProgressBarValue)
      
    Case #EventProcessingFinished
      
      DisableGadget(#myButton, #False)
      
    Case #PB_Event_CloseWindow
      
      If Not IsThread(Thread)
        Break 
      EndIf
      
  EndSelect
  
ForEver
Grüße ... Kiffi

Re: SetGadgetText und SetGadgetState sehr CPU lastig?

Verfasst: 05.04.2013 15:03
von Kevin
es gibt noch eine einfachere Lösung:

Code: Alles auswählen

anzahl=300000000
; Fenster und Gadgets öffnen
Window_0 = OpenWindow(#PB_Any, 0, 0, 740, 270, "Daten importieren", #PB_Window_SystemMenu | #PB_Window_TitleBar | #PB_Window_ScreenCentered)
ProgressBar_0 = ProgressBarGadget(#PB_Any, 200, 20, 290, 30, 0, anzahl, #PB_ProgressBar_Smooth)
Text_0 = TextGadget(#PB_Any, 200, 50, 290, 20, "", #PB_Text_Center)
Text_1 = TextGadget(#PB_Any, 20, 90, 110, 20, "Vorlaufdaten:", #PB_Text_Right)
Text_2 = TextGadget(#PB_Any, 10, 120, 120, 25, "Hauptdaten A:", #PB_Text_Right)
Text_3 = TextGadget(#PB_Any, 20, 150, 110, 20, "Hauptdaten B:", #PB_Text_Right)
Text_4 = TextGadget(#PB_Any, 20, 180, 110, 20, "Langtexte:", #PB_Text_Right)
Text_5 = TextGadget(#PB_Any, 140, 90, 220, 20, "")
Text_6 = TextGadget(#PB_Any, 140, 120, 200, 20, "")
Text_7 = TextGadget(#PB_Any, 140, 150, 230, 20, "")
Text_8 = TextGadget(#PB_Any, 140, 180, 230, 20, "")
Button_0 = ButtonGadget(#PB_Any, 310, 230, 100, 25, "Abbruch")
WaitWindowEvent() 


While ee<anzahl/3
  a+1
  b+1
  c+1
  ee+1
 
; ++++++++++
  If ElapsedMilliseconds()-verzoegerung=>100; nur alle 100ms aktuallisieren
    verzoegerung=ElapsedMilliseconds()
; ++++++++++

    ;Gadgets aktualisieren
    SetGadgetText(Text_0,Str(a+b+c)+" von "+Str(anzahl))
    SetGadgetState(ProgressBar_0,a+b+c)
    SetGadgetText(Text_6,Str(a)+" von "+Str(anzahl/3))
    SetGadgetText(Text_8,Str(b)+" von "+Str(anzahl/3))
    SetGadgetText(Text_7,Str(c)+" von "+Str(anzahl/3))
    
    Repeat
      WindowEvent=WindowEvent()
      Select WindowEvent
        Case #PB_Event_Gadget
          ;Abbruch Button abfragen
          If EventGadget()=Button_0
            result=MessageRequester("Achtung!","Möchten Sie wirklich abbrechen?",#PB_MessageRequester_YesNo)
            If result=#PB_MessageRequester_Yes          
              End      
            EndIf
          EndIf
      EndSelect
    Until WindowEvent=0
    
  EndIf
    
Wend
mfg kevin

Re: SetGadgetText und SetGadgetState sehr CPU lastig?

Verfasst: 05.04.2013 15:10
von Micha122
Zunächs Danke an alle für die zahlreichen Antworten! :allright:

@ STARGÅTE
Also, das Auge kann gerade mal ~24 Einzelbilder pro Sekunde wahrnehmen, es ist also quatsch hier innerhalb weinger Sekunden 10000 änderungen an einem Gadget durchknallen zu lassen.
Muss Dir Recht geben, tausende Aktualisierungen die Sekunde sind wirklich verschwendete CPU- Zeit.
Werde das ganze mal mit Timern ausprobieren und WaitWindowEvent ersetzen.

@alle
Das zweite WaitWindowEvent hatte ich eingefügt, weil die Gadgets nicht aktualisiert wurden (zumindest unter Linux).

@Kiffi
Dein Code sieht interessant aus, muss aber erst mal noch ein bisschen PB lernen um da alles zu verstehen.
Hab am Anfang nicht erwähnt das mein Code eine dll ist, ich glaube da klappt das so ohnehin nicht.

Grüße, Michael

Re: SetGadgetText und SetGadgetState sehr CPU lastig?

Verfasst: 05.04.2013 15:17
von ts-soft
Micha122 hat geschrieben:Werde das ganze mal mit Timern ausprobieren und WaitWindowEvent ersetzen.
Aber nicht mit WindowEvent() sondern mit WaitWindowEvent(50), wobei 50 nur exemplarisch genommen wurde.
WindowEvent() ist hier eher nicht geeignet und bei Deinem Verständnis für Fenster und EventLoop wird das
ansonsten weiterhin in einem CPU-Braten ausarten :wink: