Array clonen [erledigt]

Alle Fragen um die Programmierung, die sich sonst nicht kategorisieren lassen. Von Makro bis Codeblock, von IF bis ENDIF

Moderator: Moderatoren

Antworten
Ewald
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 475
Registriert: Sa, 08. Apr 2006 14:07
Wohnort: Datteln
Danksagung erhalten: 3 Mal
Kontaktdaten:

Array clonen [erledigt]

Beitrag von Ewald »

Ich lese alle Datensätze einer DBF in ein Array.
Aus diesem Array erzeuge ich mit Filtern ein neues Array, das dann nur die gewünschen Sätze enthält.
Um keine ungewollten Referenzen zu erzeugen mache ich das seit Jahren mit aadd(aauswahl,aclone(aalle[xi]))
Jetzt kommt erstmalig eine Datenbank ins Spiel die über 100.000 Sätze enthält.
Das Einlesen in das erste Array funktioniert innerhalb von Sekunden.
Dieses Array in das zweite Array zu übernehmen (mit aclone) funktioniert dann aber nur einmal problemlos.
Ab der zweiten Schleife kommt es zu erheblichen Zeitverzögerungen bis hin zum Rechnerabsturz.
Ohne aclone läuft es wie geschmiert.

Ich habe das hier aus meinen Anwendung auf ein Testprogramm eingeschmolzen.

Code: Alles auswählen

proc main
local getlist:=0,xi:=0
aalle:={}
afilt:={}
for xi = 1 to 5
altzeit=seconds()
fleseein()
? "Runde",xi,len(aalle),len(afilt),seconds()-altzeit
next

inkey(0)
return
*-------------------------------------------------------
function fleseein()
local i:=0
asize(aalle,0)
asize(afilt,0)
use d:\pps\werwas
go top
do while !eof()
aadd(aalle,{user,prog,teil_kom,option,datum,zeit,nn})
skip
enddo
close werwas

for i = 1 to len(aalle)
*aadd(afilt,aclone(aalle[i]))
aadd(afilt,aalle[i])
next

return .t.
Die Schleife mit der Funktion wird 5 x aufgerufen. Das ist das Ergebnis.

Code: Alles auswählen

mit aclone
Runde          1     105719     105719          1,46
Runde          2     105719     105719        174,54
Runde          3     105719     105719         73,15
Runde          4     105719     105719         60,71
Runde          5     105719     105719         47,57


ohne aclone
Runde          1     105719     105719          1,37
Runde          2     105719     105719          1,32
Runde          3     105719     105719          1,26
Runde          4     105719     105719          1,27
Runde          5     105719     105719          1,23
Warum ist das wohl so ? Ich setze doch beide Arrays in der Schleife auf Null. Bemerkt habe ich dieses
Problem in anderen Anwendungen wohl deshalb noch nicht, weil die Arrays unter 20.000 Sätze enthalten. Da
spielt die Zeit noch keine Rolle.

Wo liegt wohl mein Denkfehler ? Wieder mal was ganz banales ???
Zuletzt geändert von Ewald am Do, 22. Aug 2019 19:32, insgesamt 1-mal geändert.
georg
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2823
Registriert: Fr, 08. Feb 2008 21:29
Hat sich bedankt: 95 Mal
Danksagung erhalten: 13 Mal

Re: Array clonen

Beitrag von georg »

Hallo, Ewald -


Du verarbeitest die Daten ganz linear, und das Programm tut sonst nichts während der Zeit? Ich würde darauf tippen, dass der Garbage Collector nicht genug Zeit bekommt, um aufzuräumen. Wenn Du ein Array "platt machst", dann sind die Daten immer noch, auch wenn Du nicht mehr drankommst. Es ist die Aufgabe des Garbage Collectors, den belegten Speicherplatz freizugeben. Das macht der normalerweise, wenn das Programm grade untätig ist. Wenn Du hier linear Daten verarbeitest, ohne Pause, kommt der nicht zum Zug.

Ich würde alle n Iterationen mal ein Sleep(1) einlegen und schauen, wie sich dann die Durchlaufzeiten verändern.
Liebe Grüsse aus der Eifel,

Georg S. Lorrig
Redakteur der Wiki des Deutschprachigen Xbase-Entwickler e.V.
ramses
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2513
Registriert: Mi, 28. Jul 2010 17:16
Hat sich bedankt: 12 Mal
Danksagung erhalten: 77 Mal

Re: Array clonen

Beitrag von ramses »

Hallo Ewald

ich hatte ein vergleichbares Problem das hatte zuvor auch Jahre funktioniert.

versuche mal deine Zeile
aadd(aauswahl,aclone(aalle[xi]))

aufzuteilen in:
arr := aclone(aalle[xi])
aadd(aauswahl,arr)
Valar Morghulis

Gruss Carlo
Ewald
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 475
Registriert: Sa, 08. Apr 2006 14:07
Wohnort: Datteln
Danksagung erhalten: 3 Mal
Kontaktdaten:

Re: Array clonen

Beitrag von Ewald »

Moin zusammen,
danke für Tipps. Vorweg, die CPU-Auslastung = 26%, RAM-Auslastung = 28% (2,2 von 8,0 GB), WIN10 64bit, CPU=i3
Bei der Auslastung bleibt es wenn das System nicht stehen bleibt.

@Georg: Im richtigen Programm habe ich eine Button "aktualisieren". Der löst das neue Einlesen aus. Daher habe ich das Problem. Wenn ich den Button einmal gedrückt geht es pfeilschnell. Wenn ich später noch mal drücke ist Sense. Das Testprogramm mit Unterbrechung sleep(1) habe ich ausprobiert:

Code: Alles auswählen

mit sleep(1)
Runde          1     105719     105719          1,50
Runde          2     105719     105719         94,56
Runde          3     105719     105719         50,15
Runde          4     105719     105719         97,01
Runde          5     105719     105719         11,39
@Carlo: Der Test mit dem lokalen Zwischenarray hat den Durchbruch leider nicht gebracht.

Code: Alles auswählen

Mit lokalem arr
Runde          1     105719     105719          1,46
Runde          2     105719     105719        149,32
Runde          3     105719     105719         34,92
Runde          4     105719     105719         62,96
Runde          5     105719     105719         63,54
Irgendwie sieht es so aus als ob die Software mit den beiden Arrays einfach überfordert ist. Das war jetzt XBase2.0. Vorsichtshalber habe ich es mit 1.9 auch noch mal versucht. Gleiches Ergebnis.
Ich kann in diesem Fall damit leben das Array mit Referenz (aadd(afilt,aalle)) zu erzeugen. Aber irgendwie ärgert mich das. Wer kann sagen was morgen ist.
ramses
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2513
Registriert: Mi, 28. Jul 2010 17:16
Hat sich bedankt: 12 Mal
Danksagung erhalten: 77 Mal

Re: Array clonen

Beitrag von ramses »

Hallo Ewald

versuch doch die beiden asize() zu ersetzten. Wert 0 in asize ist doch sinnlos und macht der Runtime vermutlich nur viel Arbeit.
Daher die lange Wartezeit beim 2. Durchlauf. Beim ersten Durchlauf ist das array ja noch leer und macht keine Arbeit.

Ersetzte asize(aalle,0) mit aalle := {} und beim 2 Array auch.
Valar Morghulis

Gruss Carlo
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12903
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 44 Mal

Re: Array clonen

Beitrag von AUGE_OHR »

hi,
Ewald hat geschrieben: Mi, 21. Aug 2019 20:26 RAM-Auslastung = 28% (2,2 von 8,0 GB), WIN10 64bit
eine 32 Bit Apps "sieht" nur 3 GB und kann davon nur 2 GB RAM für ein Array nutzen.
von den 2,2 GB sind ca. 1,3-1,4 GB schon vom OS belegt also sprechen wird über ca. 700-800 MB die gehen.

siehe dazu unter "3 GB Patch" wie man mit 32 Bit Apps unter 64 Bit OS über die 2 GB Grenze kommen "könnte" ...

---

jedes Element eines Array benötigt ein Handle.
Er würde doch reichen wenn man nur die RECNO() in ein neues Array aufnimmt um damit weiter zu arbeiten, oder :?:
gruss by OHR
Jimmy
Benutzeravatar
Jan
Marvin
Marvin
Beiträge: 14641
Registriert: Fr, 23. Sep 2005 18:23
Wohnort: 49328 Melle
Hat sich bedankt: 21 Mal
Danksagung erhalten: 87 Mal
Kontaktdaten:

Re: Array clonen

Beitrag von Jan »

Ich habe keine Ahnung ob das bei AClone() auch ein Problem sein kann. Aber Arrays haben in Xbase++ zwei Probleme:
- Alaska hat die Größe begrenzt. Es gibt Mittel und Wege das massiv zu erhöhen, aber Alaska rückt das nur auf Anfrage raus. 100.000 Sätze sind aber noch kein Problem.
- Ein sehr großes Array auf einen Schlag zu erstellen führt gerne mal zu Laufzeitfehlern. Wenn man aber nach und nach Elemente Added, dann geht das doch.

Jan
Mitglied der XUG Osnabrück
Mitglied der XUG Berlin/Brandenburg
Mitglied des Deutschsprachige Xbase-Entwickler e. V.
Ewald
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 475
Registriert: Sa, 08. Apr 2006 14:07
Wohnort: Datteln
Danksagung erhalten: 3 Mal
Kontaktdaten:

Re: Array clonen

Beitrag von Ewald »

Ne, Speicherprobleme und Garbage Collector schließe ich mittlerweile auch aus.

Code: Alles auswählen

proc main
local getlist:=0,xi:=0
aalle:={}
afilt:={}
azus1:={}
azus2:={}
for xi = 1 to 5
altzeit=seconds()
fleseein()
? "Runde",xi,len(aalle),len(afilt),len(azus1),len(azus2),seconds()-altzeit
next

inkey(0)
return
*-------------------------------------------------------
function fleseein()
local i:=0,arr:={}
asize(aalle,0)
asize(afilt,0)
asize(azus1,0)
asize(azus2,0)
use d:\pps\werwas
go top
do while !eof()
aadd(aalle,{user,prog,teil_kom,option,datum,zeit,nn})
aadd(afilt,{user,prog,teil_kom,option,datum,zeit,nn})
aadd(azus1,{user,prog,teil_kom,option,datum,zeit,nn})
aadd(azus2,{user,prog,teil_kom,option,datum,zeit,nn})
skip
enddo
close werwas
return .t.
Ich habe das mal gleichzeitig in 4 Arrays einlesen lassen. Da zuckt die Kiste noch nicht mal.
Das ist das Ergebnis

Code: Alles auswählen

Gleichzeitig in 4 Arrays einlesen
Runde          1     105719     105719     105719     105719          4,15
Runde          2     105719     105719     105719     105719          2,62
Runde          3     105719     105719     105719     105719          2,25
Runde          4     105719     105719     105719     105719          2,15
Runde          5     105719     105719     105719     105719          2,23
Das hängt mit dem aclone zusammen.
Benutzeravatar
Werner_Bayern
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2120
Registriert: Sa, 30. Jan 2010 22:58
Wohnort: Niederbayern
Hat sich bedankt: 29 Mal
Danksagung erhalten: 70 Mal

Re: Array clonen

Beitrag von Werner_Bayern »

Servus Ewald,

ja, das liegt eindeutig am aClone. Das haut Dir die Memory-Handles rauf auf über 300000. RAM ist hier nicht das Problem.

Man könnte Deinen Code noch richtig gut optimieren, würde ca. 30% an Geschwindigkeit bringen, löst aber nicht das Grundproblem. Du solltest Dich diesbezüglich an Alaska wenden oder Dir überlegen, ob es nicht bessere Alternativen zu Deiner Aufgabenstellung gibt :wink:

Code: Alles auswählen

#include "Common.ch"
#include "os.ch"

PROCEDURE Main
local xi:=0, aalle, afilt, altzeit

SET CHARSET TO ANSI
for xi = 1 to 5
   altzeit=seconds()
   afilt := NIL
   aalle := NIL
   fleseein(@aalle, @afilt)
   ? "Runde",xi,len(aalle),len(afilt),seconds()-altzeit
next

inkey(0)
return

*-------------------------------------------------------
function fleseein(aalle, afilt)
local i:=1, nSaetze

use d:\pps\werwas
nSaetze := lastrec()
go top
aalle := array(nSaetze)
? memory(MEM_HANDLES_USED)
dbeval({|| aalle[i++] := {user,prog,teil_kom,option,datum,zeit,nn}})
dbCloseArea()

afilt := array(nSaetze)
aeval(aalle, {|x, i|afilt[i] := aclone(aalle[i])})
return .t.
Mit diesem Code bleiben die Handles zumindest auf ca. 300000, mit Deinem ursprünglichen werden es immer mehr. Ein Sleep(x) etc. hilft hier nicht wirklich weiter, hab eigentlich alle Kombinationen getestet.
es grüßt

Werner

<when the music is over, turn off the lights!>
ramses
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2513
Registriert: Mi, 28. Jul 2010 17:16
Hat sich bedankt: 12 Mal
Danksagung erhalten: 77 Mal

Re: Array clonen

Beitrag von ramses »

Lass doch bei aadd() mal das aclone() weg.
Valar Morghulis

Gruss Carlo
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15688
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: Array clonen

Beitrag von brandelh »

Ohne AClone() werden ja Referenzen übergeben, das spart Resourcen, kann aber zu Fehler führen.
Ich verarbeite auch Dateien mit vielen Datenzeilen (Import aus Textdatei, 1 Feld eine Zeile) sequenzieller Import, die können schon mal 400 MB Daten enthalten.

Daraus wird eine DBF mit etwa 1 GB erzeugt, alle Versuche über memoread und zerhacken der Datei sind gnadenlos fehlgeschlagen,
ab einer gewissen Größe war das viel langsamer als 4 K-Blocks zu verarbeiten (ich nutze meine Textreader Klasse) und irgendwann war Feierabend.

Sequenziell die DBF lesen, alle Verarbeitungen, Entscheidungen im Satz erledigen und z.B. in neue Datei umkopieren sollten schneller und von der Größe unbegrenzt möglich sein (2 GB für DBF ist natürlich Ende)
Wenn es nicht schnell genug geht, eine SSD einbauen oder eine RAM-DISK verwenden.
Gruß
Hubert
Ewald
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 475
Registriert: Sa, 08. Apr 2006 14:07
Wohnort: Datteln
Danksagung erhalten: 3 Mal
Kontaktdaten:

Re: Array clonen

Beitrag von Ewald »

Moin zusammen,
@Carlo: Habe ich in meinem ersten Post beschrieben. Siehe Ergebnis zwei. Das geht in Sekunden. Aber wie Hubert schon schrieb, dann werden nur Referenzen erzeugt. Bin ich früher schon mal drüber gestolpert, da sich dann Änderungen in einem der beiden Arrays unmittelbar auch in das zweite Array eintragen. Wenn es nur um das Anzeigen von Daten geht - super. Aber wenn es um Datenbearbeitung geht - böse böse Fallstricke

@Werner: Zack, und man trifft sich im Forum ;-) Das mit meinem Zertifikat hat übrigens funktioniert. Zu meinem hier beschriebenen Fall. Das war ja alles nur ein hingeworfenes Testprogramm mit dem ich den Zeitverlust rauspulen wollte. Mir ging es nicht in den Kopf, das ich eine Datenbank mit 100.000 Sätzen in Sekunden in 5 verschiedene Arrays laden kann (also 500.000) Sätze im Speicher - und es dann irgendwie in der Praxis scheitert, ein Array zu klonen das mehr 20.000 Sätze hat. Wie es sich ja rauskristallisiert liegt mein Problem im Klonen.

@Hubert: SSD habe ich drin. Ich schreibe im Moment meine Quellcodes dahingehend um, das ich die mit wenig Änderungen sowohl für den Betrieb mit DBF/NTS als auch mit SQL Datenbanken verwenden kann. Also, Verbindung zur Datenbank, benötigte Daten holen/schreiben und Datenbank wieder zu. Weiter geht es mit Arrays. War schweißtreibend.

Also, vielen Dank für die Antworten. Ich habe mal nachgesehen. In meinen Quellen gibt es 35 Stellen an denen ich seit Jahren mit aclone arbeite. Störend hat sich das nie ausgewirkt. Waren eben klein genug die Daten. Ist aber jetzt gut für mich zu wissen, das eine gewisse Aufmerksamkeit angezeigt ist.

Grüsse
Ewald
ramses
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2513
Registriert: Mi, 28. Jul 2010 17:16
Hat sich bedankt: 12 Mal
Danksagung erhalten: 77 Mal

Re: Array clonen

Beitrag von ramses »

Es bleibt noch eine weitere Möglichkeit, nicht gerade im Sinn des Titels:
Das ganze mit der Postgres (nicht ISAM EMU) umsetzten, da kannst du mit den Resultatsets wie mit Array arbeiten und hast keine Einschränkungen betreffend Speicher.
Valar Morghulis

Gruss Carlo
Ewald
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 475
Registriert: Sa, 08. Apr 2006 14:07
Wohnort: Datteln
Danksagung erhalten: 3 Mal
Kontaktdaten:

Re: Array clonen

Beitrag von Ewald »

Was lange währt …
Ich habe das Array jetzt mit einem Zwischenschritt (var2bin) dupliziert ohne Referenzen zu erzeugen. Und das dauert nur
Bruchteile der Zeit ohne aclone länger.
Entweder ich bin total vernagelt oder mein Problem ist tatsächlich zufriedenstellend gelöst und aclone kann weg.

Code: Alles auswählen

proc main
local getlist:=0,xi:=0
aalle:={}
afilt:={}
for xi = 1 to 5
altzeit=seconds()
fleseein()
? "Runde",xi,len(aalle),len(afilt),seconds()-altzeit
? aalle[100000,01],aalle[100000,02]
? afilt[100000,01],afilt[100000,02]
sleep(1)
next

inkey(0)
return
*-------------------------------------------------------
function fleseein()
local i:=0,arr:={},atemp:={},vtemp
asize(aalle,0)
asize(afilt,0)
use d:\pps\werwas
go top
do while !eof()
aadd(aalle,{user,prog,teil_kom,option,datum,zeit,nn})
skip
enddo
close werwas

for i = 1 to len(aalle)
aadd(atemp,aalle[i])
next

vtemp:=var2Bin(atemp)
afilt:=bin2var(vtemp)

aalle[100000,01]="MEIER     "     // Test ob Ref unterbrochen ist
aalle[100000,02]="EGALPROG  "  //

return .t.]

Code: Alles auswählen

Runde          1     105719     105719          1,71
MEIER      EGALPROG
PETERS     FERTAUFT
Runde          2     105719     105719          1,64
MEIER      EGALPROG
PETERS     FERTAUFT
Runde          3     105719     105719          1,73
MEIER      EGALPROG
PETERS     FERTAUFT
Runde          4     105719     105719          1,61
MEIER      EGALPROG
PETERS     FERTAUFT
Runde          5     105719     105719          1,63
MEIER      EGALPROG
PETERS     FERTAUFT
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16502
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 111 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Re: Array clonen [erledigt]

Beitrag von Martin Altmann »

Pfiffiger, intelligenter und genialer Einfall - Chapeau!

Viele Grüße,
Martin
:grommit:
Webseite mit XB2.NET und ausschließlich statischem Content in Form von HTML-Dateien: https://www.altem.de/
Webseite mit XB2.NET und ausschließlich dynamischem Content in Form von in-memory-HTML: https://meldungen.altem.de/

Mitglied der XUG Osnabrück
Vorsitzender des Deutschsprachige Xbase-Entwickler e. V.
Ewald
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 475
Registriert: Sa, 08. Apr 2006 14:07
Wohnort: Datteln
Danksagung erhalten: 3 Mal
Kontaktdaten:

Re: Array clonen [erledigt]

Beitrag von Ewald »

Oh, danke dafür Martin. Vielleicht kann es ja mal jemand brauchen ;-)
georg
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2823
Registriert: Fr, 08. Feb 2008 21:29
Hat sich bedankt: 95 Mal
Danksagung erhalten: 13 Mal

Re: Array clonen [erledigt]

Beitrag von georg »

Hallo,


mir gefällt die Lösung auch, ich habe sie dann direkt mal in den Wiki-Eintrag für AClone() übernommen.
Liebe Grüsse aus der Eifel,

Georg S. Lorrig
Redakteur der Wiki des Deutschprachigen Xbase-Entwickler e.V.
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15688
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: Array clonen [erledigt]

Beitrag von brandelh »

Eine Optimierung hätte ich noch ...

soweit ich mich daran erinnere ist es bei bekannter Anzahl besser das Array vorher anzulegen und direkt zu nutzen,
da ein häufiges Aufrufen von AADD() der Speicherverwaltung deutlich mehr Arbeit macht.

Code: Alles auswählen

atemp := {}
for i = 1 to len(aalle)
    aadd(atemp,aalle[i])
next
wäre so bei fixer Länge von aAlle effizienter

Code: Alles auswählen

atemp := {}
nAnz   := len(aalle)
atemp := ASize( aTemp, nAnz )
for i = 1 to nAnz
    atemp[i] := aalle[i]
next
ob das tatsächlich messbare Unterschiede gibt weiß ich nicht.
Gruß
Hubert
Benutzeravatar
Werner_Bayern
Der Entwickler von "Deep Thought"
Der Entwickler von "Deep Thought"
Beiträge: 2120
Registriert: Sa, 30. Jan 2010 22:58
Wohnort: Niederbayern
Hat sich bedankt: 29 Mal
Danksagung erhalten: 70 Mal

Re: Array clonen [erledigt]

Beitrag von Werner_Bayern »

brandelh hat geschrieben: Fr, 23. Aug 2019 8:09 ob das tatsächlich messbare Unterschiede gibt weiß ich nicht.
Siehe letzter Beitrag von mir - mit noch etwas mehr Optimierung. :wink:
es grüßt

Werner

<when the music is over, turn off the lights!>
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15688
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: Array clonen [erledigt]

Beitrag von brandelh »

sorry, den hatte ich überlesen ...
Gruß
Hubert
Antworten