AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Dateien schreiben Buffergröße optimieren

Ein Thema von Luckie · begonnen am 1. Dez 2006 · letzter Beitrag vom 3. Dez 2006
Antwort Antwort
Seite 1 von 3  1 23      
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#1

Dateien schreiben Buffergröße optimieren

  Alt 1. Dez 2006, 16:20
Ich bin gerade dabei meinen FileSplitter zu optimieren. Offensichtlich wird er eingesetzt, um sehr große Dateien zu teilen, um sie auf DVDs brennen zu können.

Delphi-Quellcode:
function SplitFile(Filename, DestFolder: string; SplitSize, CntParts: Int64): Int64;
const
  //BLOCKSIZE = 1048544;
  BLOCKSIZE = 32767;
resourcestring
  ChangeDiskMsg = 'Legen sie die nächste Diskette in Laufwerk a: ein.';
var
  hFile : THandle;
  SizeOfFile : Int64; // >4GB
  hPart : THandle;
  Loop : Cardinal;
  Partname : string;
  MemBuffer : array[0..BLOCKSIZE - 1] of Byte;
  BytesToRead, BytesRead, BytesWritten: Int64;
  TotalBytesRead, OverallBytesRead: Int64;
  ProgressCurrent, ProgressOld: Cardinal;
begin
  bRunning := 1;
  OverallBytesRead := 0;
  SizeOfFile := GetFileSize(PChar(Filename));
  hFile := FileOpen(Filename, $0000);
  if hFile <> INVALID_HANDLE_VALUE then
  begin
    for Loop := 1 to CntParts do
    begin
      // Reset variables
      TotalBytesRead := 0;
      ProgressOld := 0;
      BytesToRead := SplitSize;
      // build filename of the parts
      Partname := DestFolder + '\' + ExtractFilename(Filename) + Format('.%3.3d', [Loop]);
      if FileExists(Partname) then
        DeleteFile(PChar(Partname));
      hPart := FileCreate(Partname);
      if hPart <> INVALID_HANDLE_VALUE then
      begin
        repeat
          BytesRead := FileRead(hFile, MemBuffer, Min(sizeof(MemBuffer), BytesToRead));
          BytesWritten := FileWrite(hPart, MemBuffer, BytesRead);
          Dec(BytesToRead, sizeof(MemBuffer));
          // progress stuff ////////////////////////////////////////////////////
          TotalBytesRead := TotalBytesRead + BytesWritten;
          OverallBytesRead := OverallBytesRead + BytesWritten;
          ProgressCurrent := (OverallBytesRead * 100) div SizeOfFile;
          if ProgressCurrent <> ProgressOld then
          begin
            ProgressOld := ProgressCurrent;

          end;
          SendMessage(hApp, FSM_PROGRESS, ProgressCurrent, Integer(PChar(Partname)));
          //////////////////////////////////////////////////////////////////////
        until (BytesToRead <= 0) or (bRunning = 0);
      end;
      FileClose(hPart);
      if bRunning = 0 then
        Break;
      if (DestFolder = 'a:\') and (Loop < CntParts) then
      begin
        if MessageBox(0, PChar(ChangeDiskMsg), APPNAME, MB_ICONINFORMATION or MB_OKCANCEL) = ID_CANCEL then
        begin
          bRunning := 0;
          break;
        end;
      end;
    end;
    FileClose(hFile);
  end;
  SendMessage(hApp, FSM_FINISH, 0, GetLastError());
  result := GetLastError();
end;
Das ist meiner bisherige Routine. Jetzt wollte ich die Blockgröße hochsetzen, um das ganze etwas zu beschleunigen. Allerdings bekomme ich bei einer Blockgröße von 1048544 den Laufzeitfehler 202: EStackOverflow. Wie kann ich den vermeiden und trotzdem eine angemessene Blockgröße benutzen? Oder wie kann ich die optimale Blockgröße ermitteln? Oder kann man meine Routine noch an anderen Stellen optimieren?
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Benutzerbild von SirThornberry
SirThornberry
(Moderator)

Registriert seit: 23. Sep 2003
Ort: Bockwen
12.235 Beiträge
 
Delphi 2006 Professional
 
#2

Re: Dateien schreiben Buffergröße optimieren

  Alt 1. Dez 2006, 16:24
einfach nicht auf dem Stack ablegen sondern den Speicher dynamisch anfordern.
Jens
Mit Source ist es wie mit Kunst - Hauptsache der Künstler versteht's
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#3

Re: Dateien schreiben Buffergröße optimieren

  Alt 1. Dez 2006, 16:26
Wo lege ich denn was auf den Stack an und wie lege ich es auf dem Heap an?
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Benutzerbild von SirThornberry
SirThornberry
(Moderator)

Registriert seit: 23. Sep 2003
Ort: Bockwen
12.235 Beiträge
 
Delphi 2006 Professional
 
#4

Re: Dateien schreiben Buffergröße optimieren

  Alt 1. Dez 2006, 16:34
auf dem Stack wird das abgelegt was statich zur Procedure/Methode/Funktion gehört. Auf dem Heap wird der Speicher abgelegt der mit new, StrAlloc, GetMem etc. angefordert wird. Ein dynamisches Array würd also auch schon Abhilfe schaffen da bei SetLength dynamisch Speicher angefordert wird und nur der Pointer auf dem Stack landet.

derzeit legst du hier:
MemBuffer : array[0..BLOCKSIZE - 1] of Byte; BLOCKSIZE Bytes auf dem Stack ab beim aufrufen der Funktion.

Bei meinem BDS steht die MaxStackSize zum beispiel per Default auf 100000 womit es in Konflikt mit deinen 1048544 kommen würde
Jens
Mit Source ist es wie mit Kunst - Hauptsache der Künstler versteht's
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#5

Re: Dateien schreiben Buffergröße optimieren

  Alt 1. Dez 2006, 16:43
Hm. OK. Aber so:
Delphi-Quellcode:
function SplitFile(Filename, DestFolder: string; SplitSize, CntParts: Int64): Integer;
const
  BLOCKSIZE = 4194304;
  //BLOCKSIZE = 32767;
resourcestring
  ChangeDiskMsg = 'Legen sie die nächste Diskette in Laufwerk a: ein.';
var
  hFile : THandle;
  SizeOfFile : Int64; // >4GB
  hPart : THandle;
  Loop : Cardinal;
  Partname : string;
  MemBuffer : array of Byte;
// MemBuffer : array[0..BLOCKSIZE - 1] of Byte;
  BytesToRead, BytesRead, BytesWritten: Int64;
  TotalBytesRead, OverallBytesRead: Int64;
  ProgressCurrent, ProgressOld: Cardinal;
begin
  SetLength(MemBuffer, BLOCKSIZE - 1);
Schreibt er zwar sehr schnell aber in sehr kleinen Happen (Titelleiste flimmert, weil sie ständig aktualisiert wird). Und ist im Endeffekt auch nicht schneller.

Edit:
Er schreibt gar nicht, weil BytesRead immer -1 ist. Auch wenn ich hier dann schreibe:
BytesRead := FileRead(hFile, MemBuffer, Min(length(MemBuffer), BytesToRead));
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
alzaimar
(Moderator)

Registriert seit: 6. Mai 2005
Ort: Berlin
4.956 Beiträge
 
Delphi 2007 Enterprise
 
#6

Re: Dateien schreiben Buffergröße optimieren

  Alt 1. Dez 2006, 17:08
Hi Michael,

Ich glaube, Scatter/Gather I/O könnte helfen. Allerdings muss man etwas fummeln, bis es funktioniert. Scatter/Gather wird vom SQL-Server benutzt. Ok, er verwendet 8kb Seiten, sodaß es sein kann, das diese Methode nicht schneller ist, als Deine, aber ist es nicht sowieso so, das FileRead/Write auf 8k Seiten abgebildet wird?

Wenn du Scatter/Gather verwendest, optimierst Du auf der untersten Ebene: Es werden dann -glaube ich- immer 8x8kb Seiten parallel(!) gelesen/geschrieben. Die Doku hierzu ist etwas dünn, Du must also etwas suchen.

Ich meine auch, gelesen zu haben, das Du Systempages alloziieren solltest,zumindest beim S/G I/O.
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
  Mit Zitat antworten Zitat
bigg
(Gast)

n/a Beiträge
 
#7

Re: Dateien schreiben Buffergröße optimieren

  Alt 1. Dez 2006, 17:17
Hi,

es reicht imho kleinere Häppchen auszulesen und diese dann zu verarbeiten, da die gängstigen Speichermedien
auf direkten Wege auch nur kleine Happen lesen bzw. schreiben. (Stichwort: Cluster/Sektoren)

Das Flimmern der Objekte kann man unterbinden, indem man die Komponenten in einem von dir festgelegten Intervall "aktualisiert". Dazu müsstest du ein paar Zeitmessungen durchführen und dann etscheiden, was passieren soll.
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#8

Re: Dateien schreiben Buffergröße optimieren

  Alt 1. Dez 2006, 17:19
Zitat von Luckie:
Er schreibt gar nicht, weil BytesRead immer -1 ist. Auch wenn ich hier dann schreibe:
BytesRead := FileRead(hFile, MemBuffer, Min(length(MemBuffer), BytesToRead));
Hi,
dass er hier nichts sinnvolles schreibt liegt dann am unterschied zwischen dyn. und statischen Arrays. Statt MemBuffer solltest du immer das erste Element (MemBuffer[0]) bzw. dessen Adresse übergeben (je nachdem was benötigt wird). Bei den statischen Arrays steht der Typ (und damit die Länge) ja schon zur Zeit der Übersetzung fest. Bei den dyn. hast du hingegen wieder einen Aufbau, der dem von Strings entspricht (Längenangabe + Daten).

Gruß Der Unwissende
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#9

Re: Dateien schreiben Buffergröße optimieren

  Alt 1. Dez 2006, 17:27
Zitat von alzaimar:
Ich glaube, Scatter/Gather I/O könnte helfen.
Danach habe ich auch schon geguckt, nur noch nichts brauchbares gefunden. Hast du das schon mal gemacht?

@Der_Unwissende: Danke, das habe ich mal wieder übersehen.
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
alzaimar
(Moderator)

Registriert seit: 6. Mai 2005
Ort: Berlin
4.956 Beiträge
 
Delphi 2007 Enterprise
 
#10

Re: Dateien schreiben Buffergröße optimieren

  Alt 1. Dez 2006, 17:38
Ja, vor Jahren.

Ich bin damals bei Microsoft fündig geworden, dort ist/war es ganz gut erklärt. Denn jetzt ist dort nix mehr zu finden, jedenfalls nicht auf die Schnelle.

Prinzipiell musst Du system pages alloziieren. Die Größe ist systemabhängig, steht aber irgendwo. Dann bastelst Du dir ein Array (steht in der Beschreibung), wo du also 8 Records definerst. In jedem Record steht die Seitenadresse, sowie der ByteOffset in der Datei (int64). Dann machst Du overlapped I/O (soweit ich mich erinnere).

Die API-Routinen sind "ReadFileGather" und "WriteFileScatter"
Links (Auf die Schnelle):
http://www.ebook-pal.com/242-1-144-3...201700476.aspx

http://www.chem.hope.edu/cgi-bin/info2www.cgi?(libc)Scatter-Gather
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:06 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz