|
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 |
pzktupel
Anmeldungsdatum: 07.07.2020 Beiträge: 85
|
Verfasst am: 07.07.2020, 12:45 Titel: Lesegeschwindigkeit von Platte |
|
|
Hallo, ich wollte gerne einmal nachfragen, wie hoch Eurer Datensatz / s ist.
Worum gehts....ich arbeite mit sehr großen Datein , die viele Zahlen enthalten.
Ich rede hier von 5GB Datein mit ca. 230 Mio Zeilen.
Der PC (Ryzen,Win10) schafft ca. 700000 Zeilen pro Sekunde. (~10 MB/s)
Die Zahl wird zeilenweise gelesen und gleich verarbeitet...nächste Zahl gelsen usw
Sprache: Freebasic, Platte: HDD
Kann man diese Rate steigern oder ist dies normal ?
Gruß |
|
Nach oben |
|
|
dreael Administrator
Anmeldungsdatum: 10.09.2004 Beiträge: 2514 Wohnort: Hofen SH (Schweiz)
|
Verfasst am: 07.07.2020, 19:18 Titel: |
|
|
Einfache Antwort: Auf SSD wechseln, falls aktuell noch eine mechanische Festplatte dreht!
Primär beschleunigt eine SSD Lesezugriffe, speziell, wenn diese nicht sequenziell erfolgen, sondern viel Random Access. In FreeBasic: Wenn viel mit SEEK in grossen Dateien herumgesprungen wird, wo dann eine mechanische Festplatte nur noch viel am Rattern ist.
Natürlich auch wichtig: Grösse des RAM (Arbeitsspeicher); bei üppig ausgestattetem Rechner kann es passieren, dass es nur das erste Mal länger geht und beim zweiten Mal viel schneller, weil alles im RAM gecacht ist: Situation einer In-Memory-Datenbank. _________________ Teste die PC-Sicherheit mit www.sec-check.net |
|
Nach oben |
|
|
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1235 Wohnort: Ruhrpott
|
Verfasst am: 07.07.2020, 23:46 Titel: |
|
|
Das zeilenweise Nachladen von Daten kostet relativ viel Zeit. Schneller ist es, die Daten in größeren Blöcken von der Festpaltte zu holen. Das erfordert dann allerdings einen geeigneten Parser, der auch das rechtzeitige Nachladen übernimmt.
Code: | Dim As String block
Dim As Integer blocklaenge = 2^20 'Blockgröße 1MB
Open "C:\datei.dat" For Binary Access Read As #1
Do
block += Input(blocklaenge, #1) 'nächsten Datenblock nachladen
'
'Daten parsen und verarbeiten
'
'
Loop Until Eof(1)
Close 1 |
Gruß
grindstone _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
|
St_W
Anmeldungsdatum: 22.07.2007 Beiträge: 955 Wohnort: Austria
|
Verfasst am: 08.07.2020, 20:43 Titel: |
|
|
Ich hatte mal vor einigen Jahren eine kleine Filestream Klasse geschrieben für meine damaligen Bedürfnisse. Unterstützt aber wirklich nur das notwendigste, sprich einzelne/mehrere Bytes aus einer Datei zu lesen. Funktionen zum Lesen von Zeilen oder peek() Funktionalität ist da nicht dabei. Vielleicht dennoch ein guter Start oder zumindest ein Denkanstoß
Code: | '
' File Stream
' version 0.1 (2011)
Type FileStream
Public:
FileName As String
Declare Function ReadData(Buffer As ZString Ptr, MaxLen As UInteger) As UInteger
Declare Function ReadByte() As UByte
Declare Function atEOF() As Integer
Declare Sub CloseStream()
Declare Property Position() As UInteger
Declare Property Length() As UInteger
Declare Constructor(FileName As String)
Declare Destructor()
Private:
Declare Sub fillBuffer(filePos As UInteger)
Const bufLen As Integer = 1024*4
fileBuf As String * (bufLen+1)
filePos As UInteger = 0
fileLength As UInteger = 0
fileNo As UInteger = FreeFile()
bufPos As UInteger = 0
isOpen As Integer = -1
End Type
Property FileStream.Position() As UInteger
Return this.filePos
End Property
Property FileStream.Length() As UInteger
Return this.fileLength
End Property
Constructor FileStream (FileName As String)
this.FileName = FileName
Open FileName For Binary As #this.fileNo
fileLength = Lof(fileNo)
End Constructor
Destructor FileStream ()
this.CloseStream()
End Destructor
Function FileStream.ReadByte() As UByte
If fileLength = 0 Then Return 0
If atEOF Then Return 0
If bufPos = 0 Or filePos >= bufPos+bufLen Then fillBuffer(filePos+1)
filePos += 1
Return fileBuf[filePos-bufPos]
End Function
Function FileStream.ReadData(Buffer As ZString Ptr, MaxLen As UInteger) As UInteger
Dim cntBytes As UInteger = 0
For q As UInteger = 0 To MaxLen-1
If atEOF Then Exit For
Buffer[q] = this.ReadByte()
cntBytes += 1
Next
Return cntBytes
End Function
Function FileStream.atEOF() As Integer
Return filePos = fileLength
End Function
Sub FileStream.CloseStream()
If isOpen then
Close #this.fileNo
fileLength = 0
filePos = 0
this.isOpen = 0
End If
End Sub
Private Sub FileStream.fillBuffer(filePos As UInteger)
Get #fileNo,filePos,fileBuf
bufPos = filePos
End Sub
|
_________________ Aktuelle FreeBasic Builds, Projekte, Code-Snippets unter http://users.freebasic-portal.de/stw/
http://www.mv-lacken.at Musikverein Lacken (MV Lacken) |
|
Nach oben |
|
|
pzktupel
Anmeldungsdatum: 07.07.2020 Beiträge: 85
|
Verfasst am: 09.07.2020, 19:06 Titel: |
|
|
Danke für die Antworten, werde mir das mit den blockweise einlesen mal anschauen.
SSD ist dasselbe bzl Speed
Problem was ich hier habe, dass ich die Zahlen zeilenweise verarbeiten muss und sofort wieder verworfen werden. Anstatt bei 8 Tasks gleichzeitig alles in den RAM zu laden, wird einmalig von der Platte gelesen.
Vielleicht liegt es an Freebasic ?
Mein Kumpel hat auf einem i9 auf Wunsch alle Zahlen bis 100Mio auf Platte geschrieben. Das zeilenweise Einlesen hat bei ihm 8s gedauert. Sprache: C++ |
|
Nach oben |
|
|
pzktupel
Anmeldungsdatum: 07.07.2020 Beiträge: 85
|
Verfasst am: 09.07.2020, 23:32 Titel: |
|
|
Ich habe den Rat von grindstone befolgt.
Open "E:\TUPEL\3TEX777.bin" for Binary Access Read As #1
PRINT timer
WHILE NOT EOF(1)
S=Input(20000000, #1)
FOR v=1 TO 20000000 STEP 20
M1=VAL(MID(S,v,10))
M2=VAL(MID(S,v+10,10))
REM PRINT M1,M2:SLEEP
NEXT v
WEND
print timer
CLOSE #1
Keine Frage, für große Blöcke, liest er schnell die Datei aus, wenn ich aber
aus dem langen String die nummerischen Werte (auf 10 Stellen formatiert)
zurückgewinne, ist es wieder sehr langsam. ( 1mio/s )
Offenbar verliert Freebasic beim verarbeiten oder umrechnen in Integerwerte aus Strings viel Zeit oder gibt es noch andere Dinge ?
Ob aus einem 100 MB String die Zahlen zu gewinnen ist in etwa gleich , wie zeilenweise Integer gleich einzulesen. |
|
Nach oben |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4648 Wohnort: ~/
|
Verfasst am: 10.07.2020, 13:17 Titel: |
|
|
MID ist nicht gerade das Schnellste (weil automatische Sicherheitsprüfungen durchgeführt werden, ob die Angaben im erlaubten Intervall liegen; und es ist sicher auch nicht so günstig, dass der Start der nächsten Zahl immer wieder neu berechnet werden muss. Ich könnte mir vorstellen, dass du Zeit gewinnst, wenn du den Speicherblock einmal von vorn bis hinten durchläufst und dabei immer 10 aufeinander folgende Zeichen zu einer Zahl zusammensetzt.
Ist das Format der Datei fest vorgegeben? Sonst fände ich es wesentlich geschickter, die Zahlen nicht als String zu speichern, sondern binär. _________________ 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: 1235 Wohnort: Ruhrpott
|
Verfasst am: 10.07.2020, 18:08 Titel: |
|
|
@nemored: Auch für binäre Daten ziehe ich wenn irgend möglich einen String als Speicherort vor, weil ich mir dabei um die Speicherverwaltung keinen Kopf machen muß.
@pzktupel: Um den Zugriff auf den Datenstring zu beschleunigen, muß man ein weinig in die Trickkiste greifen: Code: | Dim As ZString Ptr zp
Open "E:\TUPEL\3TEX777.bin" For Binary Access Read As #1
Print Timer
While Not Eof(1)
S=Input(20000000, #1)
For v=1 To 20000000 Step 20
'M1=Val(Mid(S,v,10))
S[v + 8] = 0 'ende - kennzeichnung für ZSting setzen
zp = StrPtr(S) + v - 1 'pointer auf anfang der gewünschten zahl setzen
M1=Val(*zp) 'wert über dereferenzierten pointer holen
'M2=Val(Mid(S,v+10,10))
S[v + 18] = 0
zp = StrPtr(S) + v + 9
M2=Val(*zp)
'Print M1,M2:Sleep
Next v
Wend
Print Timer
Close #1 | Voraussetzung ist natürlich, daß jede Zahl exakt 8 Stellen hat.
Es gibt noch einen anderen Trick, allerdings weiß ich nicht, wie es damit geschwindigkeitsmässig aussieht. Du kannst ja mal beides ausprobieren:
Code: | Type tTrick
Union
As String*20000000 S 'datenstring
As String*9 t(1 To 1000000) 'array von 10-byte-strings
End Union
End Type
Dim Shared As tTrick ar
Open "E:\TUPEL\3TEX777.bin" For Binary Access Read As #1
Print Timer
While Not Eof(1)
ar.S=Input(20000000, #1)
For v=1 To 1000000 Step 2
m1 = Val(ar.t(v))
m2 = Val(ar.t(v + 1))
'Print M1,M2:Sleep
Next v
Wend
Print Timer
Close #1 |
Gruß
grindstone _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
|
pzktupel
Anmeldungsdatum: 07.07.2020 Beiträge: 85
|
Verfasst am: 10.07.2020, 19:24 Titel: |
|
|
Schön !
Ich habe heute den ganzen Tag beknobelt und ich konnte auch tatsächlich dank eurer Hilfe Speed x6 erreichen.
Was passierte ?
Diese Idee mit den blockweise einlesen klappte richtig gut. Ich formatierte alle Zahlen auf 10 Stellen konnte mit "VALUINT" die schnellste Konvertierung zu einer Integer erreichen. Mit VAL ist das langsamer !
Ins scharfe Sieb konnte ich das auch schon erfolgreich einbinden.
3 GB File mit 274 Mio Zahlen ist in 80s ausgelesen und verarbeitet, vorher 8min 20s.
Hier der Code:
Open "E:\TUPEL\3TEX1899.txt" for Binary Access Read As #1
PRINT timer
WHILE NOT EOF(1)
S=INPUT(1000000,#1)
i=1
WHILE i<1000000
M1=VALUINT(MID(S,i,10))
M2=VALUINT(MID(S,i+10,10))
i+=20
WEND
WEND
print timer
CLOSE #1
SLEEP
Dank Euche ! |
|
Nach oben |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4648 Wohnort: ~/
|
Verfasst am: 10.07.2020, 20:10 Titel: |
|
|
pzktupel hat Folgendes geschrieben: | Ich formatierte alle Zahlen auf 10 Stellen konnte mit "VALUINT" die schnellste Konvertierung zu einer Integer erreichen. Mit VAL ist das langsamer ! |
Klingt im Nachhinein logisch. VALUINT formatiert zu einer Ganzzahl und kann abbrechen, sobald es auf ein Nichtziffernzeichen stößt (vom Start mit "-" oder "&" abgesehen), wogegen VAL auch den Dezimalpunkt und die wissenschaftliche Notation berücksichtigen muss - da hat der Parser mehr Entscheidungsregeln. _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
|
pzktupel
Anmeldungsdatum: 07.07.2020 Beiträge: 85
|
Verfasst am: 10.07.2020, 20:35 Titel: |
|
|
Das leuchtet ein ! Ihr seid die Profies
Etwas Eigenwerbung...
Man kann fragen, warum das ganze ?
Ich programmiere die schnellsten Primzahl-k-Tupel Siebe, nur kommt man an Grenzen, die immer wiedermal optimiert werden müssen.
Auf MP finden sich die Resulte:
https://matheplanet.de/matheplanet/nuke/html/viewtopic.php?topic=232720&start=0
Das größte Sahnebonbon waren die beiden Offset zu finden für das kleinste 100stellige Primzahl-10-Tupel beider Typen,unter Freebasic versteht sich.
Es ist:
10^99+84878086452295590307+d , d=0,2,6,12,14,20,24,26,30,32
10^99+707220670972957883551+d , d=0,2,6,8,12,18,20,26,30,32
Grüße
@nemored mit binär muss ich nochmal testen, ist eben ungünstig,weil ich
nur maschinencode so sehe...so wie es jetzt ist,ist auch gut. |
|
Nach oben |
|
|
pzktupel
Anmeldungsdatum: 07.07.2020 Beiträge: 85
|
Verfasst am: 10.07.2020, 22:43 Titel: |
|
|
Ich komm hier bei einer Unstimmigkeit nicht weiter....
Der code von @nemored klappt nur bedingt...bug ???
Abgesehen davon, habe ich aus *9 in *10 geändert
Type tTrick
Union
As String*20000000 S 'datenstring
As String*10 t(1 To 2000000) 'array von 10-byte-strings
End Union
End Type
ar.S=Input(20000000, #1)
k=1
For ii=1 TO 2000000 STEP 10
PRINT VAL(ar.t(k));:SLEEP
k+=1
NEXT ii
Wenn ich aus meiner Liste lese:
0 10 14 9 4 12 21 16 9 3 16 29 0 30 22 38 19 18 17 20 45 41 5 13 23 23 32 23 13 28 0 59 56 54 19 6 82 67 62 27 0 70 52 7 72 90 41 83 60 61 84 37 48 101 0 101 84 21 32 147...
Dann erhalte ich:
0 10 14 9 4 12 21 16 9 3 ?? 29 0 30 22 38 19 18 17 20 ???(5) 5 13 23 23 32 23 13 28 0 9 54 19 6 82 67 62 27 0 70 2 72 90 41 83...
Fällt was auf ? Da passen etliche nicht,wieso ?
16, (45 41),...
Keine Panik, die Zahlen haben eine Bedeutung !
0 spezifischer Einstiegspunkt zur 13
10 : 13 teilt 10*11#+1
14 spezifischer Einstiegspunkt zur 17
9 : 17 teilt 9*11#+1
4 spezifischer Einstiegspunkt zur 19
12 : 19 teilt 12*11#+1
Hoch komplex...
Allerding über die meinige Methode
WHILE NOT EOF(1)
S=INPUT(1000000,#1)
v1+=1
i=1
WHILE i<1000000
V=M1
M1=VALUINT(MID(S,i,10))
M2=VALUINT(MID(S,i+10,10))
PRINT M1;" ";M2;" ";:SLEEP
i+=20
WEND
WEND
erhalte ich:
0 10 14 9 4 12 21 16 9 3 16 29 0 30 22 38 19 18 17 20 45 41 5 13 23 23 32 23 13 28 0 59 56 54 19 6 82 67 62 27 0 70 52 7 72 90 |
|
Nach oben |
|
|
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1235 Wohnort: Ruhrpott
|
Verfasst am: 11.07.2020, 09:46 Titel: |
|
|
pzktupel hat Folgendes geschrieben: | Abgesehen davon, habe ich aus *9 in *10 geändert | Und genau das ist der Fehler. Die *9 ist schon richtig, weil FB intern noch ein Nullbyte als Terminator dranhängt (im Gegensatz zum ZString, wo das dem Programmierer überlassen wird): Code: | Dim As ZString*9 zs
Print SizeOf(zs)
Dim As String*9 fs
Print SizeOf(fs)
Sleep | Und ja, nach solchen Fehlern kann man sich totsuchen.
Übrigens kannst du dir bei Verwendung von VALUINT das Nullsetzen des Terminatorbytes Code: | S[v + 8] = 0 'ende - kennzeichnung für ZSting | beim Pointerzugriff sparen. Und die Pointerberechnung kannst du direkt in die Klammer setzen. Code: | M1=ValUInt(*(StrPtr(S) + v - 1)) | Das könnte auch nochmal ein paar Mikrosekunden Zeitersparnis bringen.
Mich würde mal ein Geschwindigkeitsvergleich Pointer vs. UNION interessieren. Meiner Erfahrung nach ist bei FB der Pointerzugriff von der Geschwindigkeit her unschlagbar. Ich nutze diese Daten-in-String-laden-und-dann-mit-Pointer-dran-entlangfahren-Methode zum Normalisieren von Musikdateien.
Gruß
grindstone _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
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.
|
|