|
Das deutsche QBasic- und FreeBASIC-Forum Für euch erreichbar unter qb-forum.de, fb-forum.de und freebasic-forum.de!
|
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
Autor |
Nachricht |
ALWIM
Anmeldungsdatum: 08.08.2006 Beiträge: 1041 Wohnort: Niederbayern
|
Verfasst am: 12.07.2020, 21:08 Titel: Strings aus Datei einlesen - Speicherfehler / out of Memory? |
|
|
Ich teste gerade ein wenig mit sehr großen Dateien. Ich möchte aus einer sehr großen Datei die Daten einlesen. Leider schmiert mir das Programm dauernd ab.
Das ganze ist wie folgt: In einer Datei habe ich 205117863 Zeilen bzw. Sätze mit Daten drin. Ich kann die Daten nicht einlesen, wegen Speicherverletzungsfehler!
Entweder ist der Speicher zu gering oder ich erhalte den berühmtberüchtigten "out of bounds" - Fehler!
Wenn ich den String mit 205117863 oder größer deklariere, sagt mir mein PC: Out of Memory
Darunter kommt entweder "segmentation violation signal" oder "out of bounds".
Gibt es eine Möglichkeit das Problem zu lösen? Einlesen sollte ich die Datei schon können... _________________ SHELL SHUTDOWN -s -t 05 |
|
Nach oben |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4603 Wohnort: ~/
|
Verfasst am: 13.07.2020, 07:49 Titel: |
|
|
Dass es bei kleinerer Array-Größe zu einem out of bounds kommt, sollte ja klar sein.
In der Regel wird man in einem solchen Fall nicht die kompletten Daten im Speicher vorrätig halten, sondern immer nur den Datenbereich, mit dem man gerade arbeitet, und weitere Daten bei Bedarf nachladen (und nicht mehr benötigte aus dem Speicher werfen).
Was zumindest in bestimmten Grenzen funktionieren könnte, wäre die Daten nicht in den Stack, sondern in den Heap zu legen. Wenn ich mich richtig erinnere, wird mit DIM ein Stack-Bereich reserviert und mit REDIM ein Heap-Bereich. Die Verwendung von REDIM statt DIM könnte daher vielleicht funktionieren. _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
|
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1215 Wohnort: Ruhrpott
|
Verfasst am: 13.07.2020, 13:10 Titel: |
|
|
Eventuell hilft es auch, die Variable als SHARED zu deklarieren.
Gruß
grindstone _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
|
dreael Administrator
Anmeldungsdatum: 10.09.2004 Beiträge: 2509 Wohnort: Hofen SH (Schweiz)
|
Verfasst am: 13.07.2020, 19:34 Titel: |
|
|
An dieser Stelle auch kein Fehler: Vorhandene Ressourcen des PCs nennen, auf dem dieses Programm zum Einsatz kommt (genaue Windows-Version, CPU-Typ, 32- oder 64-Bit und natürlich Grösse des RAMs).
In einem solchen Fall durchaus auch darüber nachdenken, weitere RAM-Riegel in den PC einbauen, wenn alles in-memory laufen soll. Sonst, wenn es auf dem alten Pentium III mit 256 MB RAM lauffähig sein soll, muss über komplett andere Verarbeitungsalgorithmen nachgedacht werden. _________________ Teste die PC-Sicherheit mit www.sec-check.net |
|
Nach oben |
|
|
ALWIM
Anmeldungsdatum: 08.08.2006 Beiträge: 1041 Wohnort: Niederbayern
|
Verfasst am: 14.07.2020, 15:43 Titel: |
|
|
Zitat: | Vorhandene Ressourcen des PCs nennen, auf dem dieses Programm zum Einsatz kommt (genaue Windows-Version, CPU-Typ, 32- oder 64-Bit und natürlich Grösse des RAMs). | kann ich nicht nennen, da es jeder Rechnertyp sein kann. Das Programm kann auf jedem Rechner zum Einsatz kommen, wenn es fertig ist. Manchmal frage ich mich echt, wie das Profis machen? So eine Datei zum einlesen, wird ja nicht ohne Grund erstellt!
Um diese Datei handelt es sich: http://ratings.fide.com/download/players_list_xml.zip
Aber ich habe jetzt noch eine andere Idee! Mal schauen, ob ich es hinbekomme... _________________ SHELL SHUTDOWN -s -t 05 |
|
Nach oben |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4603 Wohnort: ~/
|
Verfasst am: 14.07.2020, 16:14 Titel: |
|
|
Wenn das Programm auf "jedem" Rechner lauffähig sein soll, würde ich ehrlich gesagt vermeiden, über 200 Millionen Datensätze gleichzeitig im Hauptspeicher zu halten.
Profis arbeiten mit Pages, in die sie (nur) die gerade benötigten Daten laden und dann, wenn sie die Daten nicht mehr benötigen, wieder aus dem Hauptspeicher verdrängen. Eine der größeren Herausforderungen ist dabei die Frage, wie lange eine Page im Speicher verweilen muss (Daten, auf die häufig zugegriffen werden muss, sollen ja möglichst lang im Hauptspeicher verweilen; aber welche Daten in Zukunft benötigt werden, ist ja nicht unbedingt vorhersagbar). Und dann muss man natürlich auch sicherstellen, dass bei einem Systemabsturz kein inkonsistenter Datenbestand zurück bleibt. Solange du Daten nur liest, ist das ja kein Problem; in einer vielfrequentierten Datenbank wird aber in der Regel munter gelesen und geschrieben.
(Große) Hauptspeicherdatenbanken sind eher die Ausnahme und erfordern eine passende Arbeitsumgebung - daher macht dreaels Frage hier durchaus Sinn. Hauptspeicher ist halt schnell und teuer; Festplattenspeicher ist günstig und langsam (zumindest im Vergleich zum Hauptspeicher). _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
|
dreael Administrator
Anmeldungsdatum: 10.09.2004 Beiträge: 2509 Wohnort: Hofen SH (Schweiz)
|
Verfasst am: 15.07.2020, 09:27 Titel: |
|
|
Da ich es beruflich mit IT zu tun habe: Aus gutem Grund gibt ein guter Software-Hersteller immer genaue Systemanforderungen für sein Produkt bekannt.
Bei einem mir bekannten ERP-System, wo 250 User gleichzeitig darauf arbeiten, können dies beispielsweise ohne Weiteres einmal 384 GB RAM(!) und 128 CPU-Kerne sein. Vom Plattenplatz im Terabyte-Bereich und auf SSD-Basis ganz zu schweigen...
Aber vermutlich braucht Dein Projekt nicht so extreme Ressourcen. Aber in Deinem Fall würde ich Dein Programm bewusst auch einmal auf unterschiedlich ausgestatteten Rechnern testen. Wenn Dein eigener Rechner nicht mehr ausreicht, so soll es hier im Hobby-Umfeld der Test auf dem üppig ausgestatteten Gamer-PC beim Kollegen sein. _________________ Teste die PC-Sicherheit mit www.sec-check.net |
|
Nach oben |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4603 Wohnort: ~/
|
Verfasst am: 15.07.2020, 10:16 Titel: |
|
|
Ich habe in meinem Datenbanken-Buch gelesen, dass es inzwischen sogar schon Richtung 1 TB RAM geht, allerdings vermutlich bei sehr speziellen Settings. _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
|
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1215 Wohnort: Ruhrpott
|
Verfasst am: 15.07.2020, 14:41 Titel: |
|
|
ALWIM hat Folgendes geschrieben: | Manchmal frage ich mich echt, wie das Profis machen? | Wie im richtigen Leben: Nicht mehr vom Kuchen abbeissen, als man kauen kann.
Das portionsweise Nachladen von Daten erfordert etwas Rechenarbeit, ist aber im Grunde nicht allzu kompliziert. Ich habe mal ad hoc ein kleines Beispielprogramm geschrieben, das die einzelnen Datensätze isoliert und in eine Textdatei schreibt. Das macht jetzt nicht viel Sinn, es soll nur zeigen, wie das Nachladen funktioniert. Außerden wird am Ende die Anzahl der Datensätze angezeigt (977123 wenn das Programm sich nicht verzählt hat).
Code: | Dim As String block, g, datensatz
Dim As String quelldatei = "D:\download\players_list_xml_foa.xml"
Dim As String zieldatei = "D:\download\liste.txt"
Dim As Integer blocklaenge, a, e, zaehler
Open quelldatei For Input As #1
Open zieldatei For Output As #2
Print "Dateilaenge:"; Lof(1)
blocklaenge = 100000000
a = 1 'pointer auf datenstring
e = 1
block = Input(blocklaenge, #1) 'ersten block laden
Do
a = InStr(e, block, "<player>") 'anfang des datensatzes
e = InStr(a, block, "</player>") + Len("</player>") 'ende des datensatzes
If a = 0 Then 'kein neuer datensatz gefunden
Exit Do
EndIf
If e < a Then 'daten nachladen
block = Mid(block, a) 'abgearbeitete daten löschen
block += Input(blocklaenge, #1) 'daten nachladen und an datenstring anhängen
a = InStr(block, "<player>") 'anfangspointer auf neue stringposition setzen
e = InStr(block, "</player>") + Len("</player>") 'endpointer setzen
EndIf
datensatz = Mid(block, a, e - a) 'datensatz aus datenstring herauskopieren
Print #2, datensatz
Print #2, ""
zaehler += 1
Loop
Print
Print zaehler; " Datensaetze"
Print "OK"
Close
Sleep
|
Vielleicht könntest du etwas genauer beschreiben, was du vorhast.
Gruß
grindstone _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
|
ALWIM
Anmeldungsdatum: 08.08.2006 Beiträge: 1041 Wohnort: Niederbayern
|
Verfasst am: 15.07.2020, 22:45 Titel: |
|
|
Zitat: | Vielleicht könntest du etwas genauer beschreiben, was du vorhast. | Ich will bei meinem Auslosungsprogramm, einen Spieler in einer externen Datei suchen und einlesen können. Das ist mein Hauptziel. Funktioniert bisher! Habe ich bereits programmiert. Allerdings muss ich vorher die entsprechende Datei mit einem anderen selbstgeschriebenen Programm ins richtige Format bringen. Und genau das gleiche, wollte ich auch mit der Datei "list_xml_foa.xml" tun! Bis ich an das kleine Problem mit dem Speicher gekommen bin... _________________ SHELL SHUTDOWN -s -t 05 |
|
Nach oben |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4603 Wohnort: ~/
|
Verfasst am: 15.07.2020, 23:57 Titel: |
|
|
Da würde ich dann die XML zeilenweise einlesen (also immer bis zu einem vollständigen Datensatz) und diesen Satz dann in deinem Format abspeichern. Wenn das verwendete UDT eine feste Größe besitzt (also insbesondere wenn vorkommende Strings alle eine feste Länge besitzen und auch keine Arrays variabler Länge vorkommen) kannst du mit PUT# und GET# jeden Datensatz in einem Rutsch speichern bzw. laden. Wenn ein Datensatz gespeichert ist, brauchst du ihn ja nicht mehr im Hauptspeicher und kannst ihn da wieder überschreiben.
Die Daten das erste Mal anzulegen wird wahrscheinlich eine Weile dauern, aber danach kannst du dir eine Zufallszahl bestimmen lassen (sagen wir mal die 123459876) und dann direkt den 123459876-ten Datensatz einlesen, ohne dass du die ganzen anderen Sätze in den Hauptspeicher laden musst. _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
|
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1215 Wohnort: Ruhrpott
|
Verfasst am: 16.07.2020, 08:08 Titel: |
|
|
ALWIM hat Folgendes geschrieben: | Ich will bei meinem Auslosungsprogramm, einen Spieler in einer externen Datei suchen und einlesen können. Das ist mein Hauptziel. Funktioniert bisher! Habe ich bereits programmiert. Allerdings muss ich vorher die entsprechende Datei mit einem anderen selbstgeschriebenen Programm ins richtige Format bringen. Und genau das gleiche, wollte ich auch mit der Datei "list_xml_foa.xml" tun! Bis ich an das kleine Problem mit dem Speicher gekommen bin... | Na, dann ist ja mein Programmschnippsel (fast) genau das, was du gesucht hast.
Allerdings habe ich festgestellt, daß er bei bestimmten Konstellationen nicht korrekt arbeitet. Und da ich in der Zwischenzeit ein paar Geistesblitze hatte ( ), habe ich ihn noch einmal überarbeitet. Das hier müsste jetzt funktionieren: Code: | Dim As String quelldatei = "D:\download\players_list_xml_foa.xml"
Dim As String block, g, datensatz
Dim As Integer blocklaenge, a, e, emax, zaehler
Open quelldatei For Input As #1
'anfangswerte setzen
blocklaenge = 100000000
a = 1 'pointer auf datenstring
e = 1
block = Input(blocklaenge, #1) 'ersten block laden
emax = InStrRev(block, "</player>") + Len("</player>") 'pointer auf ende des letzten datensatzes
Do
a = InStr(e, block, "<player>") 'hilfspointer auf anfang des nächsten datensatzes
e = InStr(a, block, "</player>") + Len("</player>") 'ende des datensatzes
datensatz = Mid(block, a, e - a) 'datensatz aus datenstring herauskopieren
'
'############################################################
'
'Die Variable "datensatz" enthält genau einen Datensatz, der mit
' "<player>" beginnt und mit "</player>" endet
'
'############################################################
'
zaehler += 1
If e = emax Then 'daten nachladen
If Eof(1) Then 'ende der datei
Exit Do
EndIf
block = Mid(block, a) 'abgearbeitete daten entfernen
block += Input(blocklaenge, #1) 'daten nachladen und an datenstring anhängen
a = InStr(block, "<player>") 'anfangspointer auf neue stringposition setzen
e = InStr(a, block, "</player>") + Len("</player>") 'endpointer setzen
emax = InStrRev(block, "</player>") + Len("</player>") 'pointer auf ende des letzten datensatzes
EndIf
Loop
Print
Print zaehler; " Datensaetze"
Print "OK"
Close
Sleep | Du brauchst nur noch deinen Code zum Verarbeiten der Datensätze einzufügen.
nemored hat Folgendes geschrieben: | Da würde ich dann die XML zeilenweise einlesen | Das zeilenweise Einlesen dauert ewig!
Und ein Datensatz sieht so aus:<player>
<fideid>9018158</fideid>
<name>9018140</name>
<country>MAR</country>
<sex>M</sex>
<title></title>
<w_title></w_title>
<o_title></o_title>
<foa_title></foa_title>
<rating></rating>
<games></games>
<k></k>
<rapid_rating></rapid_rating>
<rapid_games></rapid_games>
<rapid_k></rapid_k>
<blitz_rating></blitz_rating>
<blitz_games></blitz_games>
<blitz_k></blitz_k>
<birthday>2001</birthday>
<flag></flag>
</player>
Die Länge ist also nicht einheitlich. Eigentlich ein klarer Fall für einen UDT mit entsprechenden Properties zum Umwandeln, aber ich weiß, daß ALWIM keine UDTs mag.
Gruß
grindstone _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4603 Wohnort: ~/
|
Verfasst am: 16.07.2020, 15:52 Titel: |
|
|
grindstone hat Folgendes geschrieben: | Das zeilenweise Einlesen dauert ewig! |
weshalb es ja auch nur ein einziges Mal gemacht werden sollte, um die Daten überhaupt einmal ins System zu bekommen. Geht das blockweise Einlesen mit INSTR-Suche da deutlich schneller? Wenn ja, dann natürlich gern auf diesem Weg. Auf jeden Fall müssen die Daten dann in ein angenehmeres Format, und da kommt man an einem UDT nur schwer vorbei.
(Ich habe bei dieser Datei mal das reine zeilenweise Einlesen ohne Weiterverarbeitung getestet, und das waren gut 11 Sekunden für 20519585 Zeilen - für eine einmalige Angelegenheit halte ich das für vertretbar.) _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
|
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1215 Wohnort: Ruhrpott
|
Verfasst am: 16.07.2020, 17:53 Titel: |
|
|
Zeilenweises Einlesen dauert mit meinem schon etwas betagten Rechenknecht etwa 40 Sekunden gegenüber ca. 4 Sekunden bei blockweisem Einlesen. Also etwa die 10fache Geschwindigkeit.
Bei einmaliger Anwendung fällt das -da gebe ich dir recht- allerdings nicht allzu sehr ins Gewicht.
Gruß
grindstone _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
|
ALWIM
Anmeldungsdatum: 08.08.2006 Beiträge: 1041 Wohnort: Niederbayern
|
Verfasst am: 19.07.2020, 03:18 Titel: |
|
|
Zitat: | Auf jeden Fall müssen die Daten dann in ein angenehmeres Format, und da kommt man an einem UDT nur schwer vorbei. happy | Ich habe schon mal in einem Programm den Befehl Type verwendet. Eben weil es nicht anders ging. Aber ich habe jetzt eine andere Idee! Es gibt ja noch eine Datei zum runterladen, wo die Datei bereits fast im richtigen Format ist! Ich muss nur noch schauen, wie ich die einzelnen Werte trennen kann.
Der Aufbau der Datei sieht so aus:
Code: | ID Number Name Fed Sex Tit WTit OTit FOA SRtng SGm SK RRtng RGm Rk BRtng BGm BK B-day Flag
9984828 Aadesh, Jeyathevan SRI M 1035 0 40 1058 0 20 2004 i
4804929 A-ALI,Sali Abbas Abdulzahra IRQ F WFM WFM 1911 0 20 1749 0 20 1705 0 20 2001 w |
_________________ SHELL SHUTDOWN -s -t 05 |
|
Nach oben |
|
|
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1215 Wohnort: Ruhrpott
|
Verfasst am: 19.07.2020, 14:55 Titel: |
|
|
Ich habe ja nicht gesagt, daß du mit UDTs nicht umgehen kannst, sondern nur, daß du sie nicht magst.
Und was die alternative Datei betrifft, da dürfte das xml - Format wegen der eindeutigen Kennzeichnung der einzelnen Werte wohl einfacher zu handhaben sein. Mit einer simplen Function lassen sich die gewünschten Werte in beliebiger Reihenfolge aus dem Datensatz extrahieren: Code: | Dim As String quelldatei = "D:\download\players_list_xml_foa.xml"
Dim As String zieldatei = "D:\download\liste.txt"
Dim As String block, g, datensatz
Dim As Integer blocklaenge, a, e, emax, zaehler
Dim As Double zeit = Timer
Declare Function wert(ds As String, item As String) As String
Open quelldatei For Input As #1
Open zieldatei For Output As #2
'anfangswerte setzen
blocklaenge = 100000000
a = 1 'pointer auf datenstring
e = 1
block = Input(blocklaenge, #1) 'ersten block laden
emax = InStrRev(block, "</player>") + Len("</player>") 'pointer auf ende des letzten datensatzes
Do
a = InStr(e, block, "<player>") 'hilfspointer auf anfang des nächsten datensatzes
e = InStr(a, block, "</player>") + Len("</player>") 'ende des datensatzes
datensatz = Mid(block, a, e - a) 'datensatz aus datenstring herauskopieren
Print #2, wert(datensatz, "name")
Print #2, wert(datensatz, "fideid")
Print #2, ""
zaehler += 1
If e = emax Then 'daten nachladen
If Eof(1) Then 'ende der datei
Exit Do
EndIf
block = Mid(block, a) 'abgearbeitete daten entfernen
block += Input(blocklaenge, #1) 'daten nachladen und an datenstring anhängen
a = InStr(block, "<player>") 'anfangspointer auf neue stringposition setzen
e = InStr(a, block, "</player>") + Len("</player>") 'endpointer setzen
emax = InStrRev(block, "</player>") + Len("</player>") 'pointer auf ende des letzten datensatzes
EndIf
Loop
Print
Print zaehler; " Datensaetze"
Print Timer - zeit
Print "OK"
Close
Sleep
Function wert(ds As String, item As String) As String
Dim As Integer a, e
a = InStr(ds, "<" + item + ">") + Len(item) + 2
e = InStr(ds, "</" + item + ">")
Return Mid(ds, a, e - a)
End Function |
Gruß
grindstone _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
|
HorstD
Anmeldungsdatum: 01.11.2007 Beiträge: 107
|
Verfasst am: 19.07.2020, 17:03 Titel: |
|
|
Für deine alternative Datei
Code: |
Dim t As String
Dim As string Id, xname, Fed, Sex, Tit, WTit, OTit, FOA, SRtng
Dim As String SGm, SK, RRtng, RGm, Rk, BRtng, BGm, BK, Bday, Flag
Open "d:\###\alwin.dat" For Input As #1
While Not EOF(1)
Line Input #1, t
Id = Trim(Left(t, 15))
xname = Trim(Mid(t, 16, 60))
Fed = Mid(t, 77, 3)
Sex = Trim(Mid(t, 81, 3))
Tit = Mid(t, 85, 3)
WTit = Mid(t, 90, 4)
OTit = Trim(Mid(t, 95, 15))
' ...
Flag = Trim(Mid(t, 159, 4))
Print "ID: "; Id, "Name: "; xname, "Fed: "; Fed, "sex: "; Sex, "... Flag: "; Flag
Wend
Close
|
|
|
Nach oben |
|
|
|
|
Du kannst keine Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum nicht antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen.
|
|