  | 
					
						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: 2531 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: 1283 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: 958 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: 4712 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: 1283 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: 4712 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: 1283 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.
  | 
   
 
     |