Seite 1 von 2

große Strings/Dateien in EditorGadget laden

Verfasst: 22.06.2017 10:37
von SBond
Hallo Leute,

Ich stehe gerade vor dem Problem, dass das Einfügen von großen Inhalten in den Editorgadget sehr lange dauert und dieses anschließend nur noch sehr langsam reagiert.

Folgendes: Ich nutze SpiderBasic zur Überwachung von Messdaten auf einem Raspberry Pi.
Der Inhalt sieht so aus:

Code: Alles auswählen

Time [s]	Offset [ms]	Delay [ms]	Dispersion [ms]	Poll [Log2s]
1	2181.058691	5.524050	0.003832	2
2	2350.240706	5.753778	0.003832	2
3	2230.809869	5.078382	0.003832	2
4	2009.526000	5.929749	0.003832	2
5	1761.233782	5.510072	0.003832	2
6	1522.508577	5.669883	0.003832	2
7	1309.264120	5.374863	0.003832	2
8	1125.606571	5.415642	0.003832	2
9	970.654422	5.266202	0.003832	2
10	840.647550	5.478681	0.003832	2
11	732.227495	5.503962	0.003832	2
[...]
...Tab-Stop getrennte Messwerte, jedoch bis zu 500K Zeilen. Die Dateigröße liegt in diesem Fall bei ca. 20MB.
Die Messwerte werden über ein HTTP-Request angefordert und liegen anschließend in einer String-Variablen bereit.

Gibt es irgendeine Möglichkeit das Laden zu beschleunigen? APIs scheinen hier ja nicht zu gehen und ein ListIconGadget wäre mit 500K Einträgen sogar noch langsamer. :(

viele Grüße,
SBond

Re: große Strings/Dateien in EditorGadget laden

Verfasst: 22.06.2017 12:40
von Kiffi
Hallo SBond,

kannst Du mir / uns mal eine Beispiel-Datei zur Verfügung stellen?

Grüße ... Peter

Re: große Strings/Dateien in EditorGadget laden

Verfasst: 22.06.2017 13:01
von Bisonte
Kommen die per Request in einem Rutsch ? Also alle auf einmal ?

Mit folgendem Test dauert es in einem ListIconGadget ca. 15 Sekunden (ohne Debugger)
wenn man das Redraw ausschaltet. Bei eingeschaltetem Redraw ca. 95 Sekunden.

Code: Alles auswählen

;: generiere 500k Zeilen für das ListIcon

NewList String.s()

TimeStart = ElapsedMilliseconds()
For i = 1 To 500000
  AddElement(String())
  String() = Str(i) + #LF$ + StrF(Random(3000,1), 6) + #LF$ + StrF(Random(3000,1), 6) + #LF$ + StrF(Random(3000,1), 6) + #LF$ + Str(Random(20))
Next

MessageRequester("", "Erstellen der Strings : " + Str(ElapsedMilliseconds() - TimeStart) )

OpenWindow(0, 0, 0, 640, 480, "Test", #PB_Window_ScreenCentered|#PB_Window_SystemMenu)

ListIconGadget(0, 10, 40, 620, 430, "ID", 100)
AddGadgetColumn(0, 1, "Offset", 100)
AddGadgetColumn(0, 2, "Delay", 100)
AddGadgetColumn(0, 3, "Dispersion", 100)
AddGadgetColumn(0, 4, "Poll", 100)
ButtonGadget(1, 10, 0, 100, 20, "Los")

AddKeyboardShortcut(0, #PB_Shortcut_Escape, 59999)

Repeat
  Event = WaitWindowEvent()
  
  Select Event
    Case #PB_Event_CloseWindow
      Quit = #True
      
    Case #PB_Event_Gadget
      Select EventGadget()
        Case 1
          TimeStart = ElapsedMilliseconds()
          ; Für anderen test einfach die Sendmessagezeilen auskommentieren
          SendMessage_(GadgetID(0), #WM_SETREDRAW, 0, 0) ; Redraw aus
          ForEach String() : AddGadgetItem(0, -1, String()) : Next
          SendMessage_(GadgetID(0), #WM_SETREDRAW, 1, 0) ; Redraw an
          MessageRequester("", "Einfügen der Strings : " + Str(ElapsedMilliseconds() - TimeStart))
      EndSelect

  EndSelect
  
Until Quit
Edit: Ups :oops: kann ja mal passiern ;)

Re: große Strings/Dateien in EditorGadget laden

Verfasst: 22.06.2017 13:07
von Kiffi
@Bisonte: Falsches Forum ;-)

Re: große Strings/Dateien in EditorGadget laden

Verfasst: 22.06.2017 13:15
von SBond
Ja, die Daten kommen zumindest in diesem Fall in einem Rutsch. ist aber auch so gewollt, um alle Daten abzurufen. Habe noch ein live-logging modus wie 'tail -f' unter Linux, aber der ist hier erstmal nicht relevant.

@Bisonte: Der Code geht leider nicht unter SpiderBasic. Aber dennoch danke für die Tipps :mrgreen:


Hier mal eine einfache Code-Grundlage:

Code: Alles auswählen

Declare.i CloseWindowEvent()
Declare.i ReadFileCallback(Status, Filename$, File, SizeRead)

Enumeration
	#Window_Main
	#Gadget_Editor
	#File
EndEnumeration

; ========================================================================


OpenWindow   (#Window_Main, 0, 0, 600, 500, "slow EditorGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
EditorGadget (#Gadget_Editor, 10, 10, 580, 480)

BindEvent (#PB_Event_CloseWindow, @CloseWindowEvent())
ReadFile  (#File, "Testdatei3.txt", @ReadFileCallback())


; ========================================================================

Procedure CloseWindowEvent()
	CloseWindow(EventWindow())
EndProcedure


Procedure ReadFileCallback(Status, Filename$, File, SizeRead)
	
	Select Status
		Case #PB_Status_Loaded
			Debug "Dateigröße: " + StrD(SizeRead/1000) + " KBytes"
						
			T1 = ElapsedMilliseconds()
			fileContent.s = ReadString(#File, #PB_File_IgnoreEOL)
			CloseFile(#File)
			Debug "Datei laden: " + Str(ElapsedMilliseconds() - T1) + " ms"
			
			T1 = ElapsedMilliseconds()
 			SetGadgetText(#Gadget_Editor, fileContent)
			Debug "in EditorGadget einfügen: " + Str(ElapsedMilliseconds() - T1) + " ms"
			
			
		Case #PB_Status_Error
			Debug "File loading has failed"
	EndSelect
EndProcedure
Den HTTP-Request und alles andere habe ich mal rausgekürzt. Der Code lädt hier eine Datei und packt den Inhalt in den EditorGadget. Je größer die Datei wird, desto länger dauert das Einfügen und um so träger reagiert die ganze Oberfläche.

Bei einer Datei mit 200K Zeilen erhalte ich folgende Debugausgabe:

Code: Alles auswählen

Dateigröße: 7193.449 KBytes
Datei laden: 712 ms
in EditorGadget einfügen: 65 ms
Die untere Messung ist auch falsch... warum auch immer. Das Einfügen dauert ca. 9 Sekunden und die Oberfläche reagiert kaum noch. Keine Ahnung wie die 65 ms zustande kommen.

Edit: Das Ergebnis kannst du natürlich mit jeder belibigen Datei reproduzieren. <)

Re: große Strings/Dateien in EditorGadget laden

Verfasst: 22.06.2017 13:22
von Kiffi
@SBond: Ich meinte eine Beispiel-Datei mit Messwerten (Hast Du vielleicht falsch verstanden).

Re: große Strings/Dateien in EditorGadget laden

Verfasst: 22.06.2017 13:53
von SBond
ok.

hier sind die Testdateien. Hatte ich mit Excel generiert.

https://www.dropbox.com/s/hzdsaopzxyjiy ... t.zip?dl=0

oder hier:

EGadget.zip

Re: große Strings/Dateien in EditorGadget laden

Verfasst: 22.06.2017 16:15
von Micha122
Hallo,
also ich denke Deine Zeitmessung ist falsch.
Habe den Code etwas geändert.

Code: Alles auswählen

Procedure ReadFileCallback(Status, Filename$, File, SizeRead)
   
   Select Status
      Case #PB_Status_Loaded
         Debug "Dateigröße: " + StrD(SizeRead/1000) + " KBytes"
                  
         Start_Zeit =  ElapsedMilliseconds()
         fileContent.s = ReadString(#File, #PB_File_IgnoreEOL)
         CloseFile(#File)
         T1 = ElapsedMilliseconds()
         Debug "Datei laden: " + Str(T1 - Start_Zeit) + " ms"
         
         Start_Zeit =  ElapsedMilliseconds()
         SetGadgetText(#Gadget_Editor, fileContent)
         T2 = ElapsedMilliseconds()
         Debug "in EditorGadget einfügen: " + Str(T2 - Start_Zeit) + " ms"
         
         
      Case #PB_Status_Error
         Debug "File loading has failed"
   EndSelect
EndProcedure
Ich bekomme folgendes Ergebnis: (getestet mit Testdatei3.txt)
Laden 911 ms
Einfügen 309 ms

Grüße

Edit: Sorry meine Zeitmessung ist das selbe in Grün. Aber bei mir stimmen die Zeiten.

Leider lässt sich der Editor nicht benutzen, zeigt zwar Text aber reagiert nicht.
War da etwas voreilig. :oops:

Re: große Strings/Dateien in EditorGadget laden

Verfasst: 22.06.2017 18:47
von Micha122
Dein Thema hat mich nun nicht losgelassen.
Das Editor Gadget scheint mit der Datei Testdatei3 wirklich überfordert zu sein.

Hier mal Dein ReadFileCallback etwas anders. Der Code funktioniert in Echtzeit inklusive "lebenden" Editor.
Geladen wird die Datei komplett, es wird allerdings nur 1/10 in das Editor Gadget geschrieben. :oops:
Versuche ich grössere Datenmengen ins Gadget zu schreiben tritt der beschriebene Effekt nach und nach auf.

Code: Alles auswählen

Procedure ReadFileCallback(Status, Filename$, File, SizeRead)
 
  *Buffer = AllocateMemory(SizeRead)
   Select Status
      Case #PB_Status_Loaded
         Debug "Dateigröße: " + StrD(SizeRead/1000) + " KBytes"
                  
         Start_Zeit =  ElapsedMilliseconds()
         ReadData(#File, *Buffer,0, SizeRead)
         String.s = PeekS(*Buffer,0, SizeRead/10, #PB_UTF8)
         CloseFile(#File)
         T1 = ElapsedMilliseconds()
         Debug "Datei laden: " + Str(T1 - Start_Zeit) + " ms"
        
         Start_Zeit =  ElapsedMilliseconds()
         SetGadgetText(#Gadget_Editor, String)
         T2 = ElapsedMilliseconds()
         Debug "in EditorGadget einfügen: " + Str(T2 - Start_Zeit) + " ms"
         
         
      Case #PB_Status_Error
         Debug "File loading has failed"
   EndSelect
EndProcedure
Grüße, Micha

Re: große Strings/Dateien in EditorGadget laden

Verfasst: 22.06.2017 19:19
von Kiffi
Hallo SBond,

wie man es dreht und wendet: 20 MB sind für eine Webseite kein Pappenstiel. Und wie es aussieht wird diese Datenmenge in Zukunft wohl auch noch größer werden.

Folgendes musst Du bedenken:

* Die 20 MB werden bei jedem Aufruf der Seite von Deinem Server geladen: Hoher Traffic

* Die 20 MB müssen jedes mal in ein geeignetes Format gebracht werden, damit sie angezeigt werden können. Sei es durch die PB-String-Befehle (CountString(), StringField(), etc.) oder in irgendeiner anderen Art und Weise: Das dauert.

* 500.000+ Zeilen? Wer schaut sich die Daten denn allen ernstes an?

Wie dem auch sei: Ich habe verschiedene Tests mit DataGrid-Komponenten gemacht, von denen ich der Meinung bin, dass sie auch für große Datenmengen geeignet sind. Durch die Bank weg benötigt das Eintragen der Daten in diese Komponenten übermäßig viel Zeit, in der der Browser / Rechner dann aber auch kräftig arbeiten muss (im Gegensatz zum EditorGadget oder ListIconGadget sind die DataGrids danach allerdings noch bedienbar, wenigsten ein kleiner Trost).

Der für die Anzeige großer Datenmengen beste Weg ist es, die Daten bei Bedarf zu laden. Sprich: Es werden beispielsweise die ersten 100 Zeilen geladen und angezeigt und wenn der Benutzer scrollt, so werden die benötigten Daten im Hintergrund nachgeladen (lazy loading). Das geht recht flott, spart Resourcen und einige DataGrid-Komponenten bieten das 'von Haus aus' an. Allerdings müsstest Du Deine Daten vorher in ein geeignetes Format bringen (i.A. JSON).

Wenn Du daran Interesse hättest, könnte ich Dir ein kleines Beispiel basteln. Sag Bescheid.

Grüße ... Peter