Forum: PC-Programmierung Speicher reservieren dauert extrem lange (VB)


von LangsamerSpeicher? (Gast)


Lesenswert?

Hallo zusammen,

Ich schreibe derzeit an einem Programm, das mit sehr großen Textdateien 
umgehen muss (bis zu 10 Millionen Zeilen).

Das merkwürdige dabei ist, dass das Reservieren des Speichers für einen 
String entsprechender Größe (z.B. 20 MB, entspricht ca. 1 Mio. Zeilen) 
länger dauert als das Parsen des Strings und die anschließende 
Generierung eines zweiten Strings (kürzer) aus den entsprechenden Daten.

Nun ist ja Visual Basic 5 nicht gerade für seine tolle Geschwindigkeit 
bekannt, aber auch mit der API-Variante HeapAlloc geht es nicht wirklich 
schneller als die Standardversion "Space$(AnzahlderBytes)".

Außerdem musste ich feststellen, dass die Dauer für das Reservieren 
keineswegs linear mit der Speichergröße ansteigt, wie ich jetzt naiv 
vermutet hätte:
1
   100.000 Zeilen - 0,13s
2
 1.000.000 Zeilen - 16s
3
10.000.000 Zeilen - läuft schon etwas länger, reiche ich ggf. nach

Ist das normal? (der Rechner hat 16GB RAM, sollte also nicht knapp 
werden)

von Vn N. (wefwef_s)


Lesenswert?

Vernünftigerweise würde man gar nicht alles in den RAM legen.

von LangsamerSpeicher? (Gast)


Lesenswert?

update: Die 10 Mio. Zeilen-Datei (188MB) ist gerade eben mit einem 
Speicherfehler abgebrochen. Alleine das Reservieren des Speichers hätte 
damit also mindestens gute 50min gebraucht, wenn es jetzt fertig gewesen 
wäre - und das auf einem Quadcore.

Im Taskmanager konnte ich sehen, dass das Programm sich langsam an 1GB 
(?) Ramverbrauch herangetastet hat, was meiner Meinung nach viel zu viel 
ist.

Eine kurze Testausgabe hat aber bestätigt, dass die Anzahl an Zeichen 
für das Reservieren mit "Space$()" korrekt ermittelt wird.

von LangsamerSpeicher? (Gast)


Lesenswert?

@ vn nn (wefwef_s):
Selbstverständlich könnte man das auch Häppchenweise aus der Datei 
lesen, aber ich habe ja eigentlich genug RAM frei, und Operationen im 
RAM sollten normalerweise doch schneller sein, oder?

Irgendwie kommt es mir seltsam vor, dass das Anlegen von so einem 
bisschen Speicher in einer Variablen so langsam sein kann. (insbesondere 
bei den 188MB/10Mio. Zeilen)

von Dr. Sommer (Gast)


Lesenswert?

Was verstehst du unter einer Zeile? Einen dynamisch verwalteten String? 
Dass das Anlegen von 10M String-Handlern + 10M dynamischen 
String-Blöcken langsam ist ist dann klar. Was hälst du davon, einfach 
einen einzelnen 188 MByte großen String anzulegen und die Datei dort 
reinzulesen? Du könntest dann zusätzlich ein Array mit 10M Integern 
anlegen und dort die Indices der Zeilenanfänge speichern, falls du 
schnell bestimmte Zeilen finden musst.
Die Tatsache, dass du von Zeilen sprichst, legt die Vermutung nahe dass 
es sich um ein textbasiertes Format handelt. Wäre es nicht sinnvoller 
die Daten beim einlesen direkt in eine Art Binärformat/Datenstrukturen 
umzuwandeln und so effizienter im RAM zu speichern?

von Rene S. (Firma: BfEHS) (rschube)


Lesenswert?

LangsamerSpeicher? schrieb:
> ... (bis zu 10 Millionen Zeilen).
>
> ... ja Visual Basic 5

Hallo,

die beiden Sachen würden mir zusammen schon mal Bauchschmerzen bereiten.

Erläutere doch mal deine Beweggründe warum du das so machen willst, wie 
du es jetzt versuchst. Ist das wirklich die beste Lösung?

Schau dir mal Themen wie "Data Mining" und "BigData" an.

Also erklär mal was du wirklich willst. Und ob du vielleicht auch 
(sorry) mit richtigen Programmiersprachen kannst...

Grüße aus Berlin

von тупой сказател (Gast)


Lesenswert?

Der Speicher wird falsch alloziert. Wenn so ein Vorgang zu lange dauert, 
wird der String incrementell erhoeht. Dh Specher allozieren, rein mit 
dem String, dann ein Stueck Speicher wie bisher plus das Increment, eine 
Zeile, allozieren, alles kopieren und so weiter.

Das muss man anders anpacken. Schauen, wie gross die Datei ist, inkl. 
steuerzeichen. Dann dieses Stueck allozieren, auch wenn's 500MByte ist. 
Und dann alles am Stueck rein, in einem Binaertransfer.

von Yalu X. (yalu) (Moderator)


Lesenswert?

LangsamerSpeicher? schrieb:
> Nun ist ja Visual Basic 5 nicht gerade für seine tolle Geschwindigkeit
> bekannt, aber auch mit der API-Variante HeapAlloc geht es nicht wirklich
> schneller als die Standardversion "Space$(AnzahlderBytes)".

Hast du das getestet, indem du in einem Testprogrogramm nur HeapAlloc
bzw. Space$ aufgerufen hast? Das kann unmöglich so lange dauern. Ich
kein Windows und erst recht kein VB, hab's aber aus Neuigier mal unter
Linux in C mit malloc auf meiner alten P4-Gurke getestet:

10.000.000 Blöcke mit je 20 Bytes (insgesamt 2E8 Bytes): 1,045 s
1 Block mit 200.000.000 Bytes     (insgesamt 2E8 Bytes): 0,865 s

Dabei habe ich den kompletten reservierten mit fortlaufenden Zahlen
füllen lassen und ein Byte davon wieder ausgelesen, um sicher zu gehen,
dass der Speicher nicht nur virtuell reserviert wird.

Windows ist zwar schlecht, aber sicher nicht so schlecht, dass es für
die gleiche Aktion auf einem deutlich moderneren Prozessor 50 Minuten
und mehr braucht.

Ich glaube eher, ein anderer Programmteil braucht viel Rechenzeit, und
du führst dies irrtümlicherweise auf die Speicherreservierung zurück.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Yalu X. schrieb:
> ich glaube eher, ein anderer Programmteil braucht viel Rechenzeit, und
> du führst dies irrtümlicherweise auf die Speicherreservierung zurück.

Wenn er sowas macht:

str = str + neue_zeilen

wird im blödestem Falle folgendes ausgeführt:

- Allozieren str.len + neue_zeilen.len bytes
- Erzeuge Verwaltungsinfos für String
- Kopieren str + neue_zeilen
- gebe alten Speicher von str frei

Wenn er das 10 Millionen(!!!) mal macht muss er sich nicht wundern wenn 
das elendig lange dauert.

Ein einmaliges malloc ist natürlich extrem schnell im Vergleich.

von LangsamerSpeicher (Gast)


Lesenswert?

>Was hälst du davon, einfach einen einzelnen 188 MByte großen String anzulegen und
>die Datei dort reinzulesen?
Genau so habe ich es gemacht.

>Hast du das getestet, indem du in einem Testprogrogramm nur HeapAlloc
>bzw. Space$ aufgerufen hast?
Die Zeitmessung lief nur über den "Space$()" bzw "HeapAlloc()"-Befehl 
und das Programm hat auch nichts nebenbei zu tun gehabt.

Alleine das Anlegen der Variablen hat so lange gedauert, warum auch 
immer...

Ich habe es heute noch mal mit der "Space$()"-Funktion in Visual Studio 
2012 ausprobiert und da lief alles problemlos und in einer eher zu 
erwartenden Geschwindigkeit (200MB deutlich unter einer Sekunde) -> 
Jetzt habe ich endlich mal einen Grund, mich ins neuere Visual Studio 
einzuarbeiten ;-)

von Bastler (Gast)


Lesenswert?

Was bedeutet "umgehen"? Lesen oder auch ändern?
Für so was bieten moderne OSe "Memory Mapped Files". Die werden in den 
Adressraum eingeblendet, du hast ja mit 16GB RAM sicherlich 64Bit und 
damit satt genug davon, und können wie normalen Speicher behandelt 
werden, d.h. keine IO Aufrufe, nur das dieser quasi mit dem Inhalt der 
Datei initialisiert ist. Wurde R/W geöffnet, dann kann man auch ändern, 
was wiederum auf der Datei landet. Vergrössern/verkleiner geht 
prinzipiell auch, ist aber etwas aufwendiger in der Handhabung. 
OS-übergreifend macht das Java mit NIO.
VB kann das im Prinzip auch, da man ja DLL-Routinen aufrufen kann, aber 
wenn man MemMappedIO in VB hinbekommt, dann weiß man auch wie das in 
C[++|#]? geht.

von Bastler (Gast)


Lesenswert?

Ergänzung: die Datei nimmt dann am Paging teil, d.h nur was benutz wird 
muß im Speicher stehen, der unbenutzte Rest bleibt auf Platte. Genau so 
werden BTW auch Programm/DLL's/sharedLib's behandelt. Das sind einfach 
R/O MemMapped Files.
@Profis: ich weiß manche Teile davon sind CopyOnWrite, d.h. werden mit 
den Daten des Files initialisiert und können geändert werden, ohne das 
sich das auf das File auswirkt. Aber erst mal R/O, zum Einstieg ;-)

von Kaj (Gast)


Lesenswert?

LangsamerSpeicher? schrieb:
> Nun ist ja Visual Basic 5 nicht gerade für seine tolle Geschwindigkeit
> bekannt

LangsamerSpeicher schrieb:
> Jetzt habe ich endlich mal einen Grund, mich ins neuere Visual Studio
> einzuarbeiten ;-)

Irgendwie bezweifel ich, das eine IDE so dermaßen das Zeitverhalten 
deiner Applikation beeinträchtigt...

von Ah. (Gast)


Lesenswert?

Es gibt tolle Komponenten, die sind sehr gut und praktisch fuer kleine 
Textfiles. Dan kann man zB die Zeile per array zugreifen. Bei grossen 
files koennen solche komponenten eine Katastrophe sein. Ich hatte mal 
ein Stringgrid, das konnte sich von einem CSV file laden. 30000 Zeilen 
zu laden  dauerten eine Viertel Stunde. Sowas muss man dann eben von 
Grund auf neu schreiben.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.