Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Prozedur beschleunigen / Threads? (https://www.delphipraxis.net/139963-prozedur-beschleunigen-threads.html)

Balu der Bär 9. Sep 2009 09:14


Prozedur beschleunigen / Threads?
 
Moin,

eines meiner Projekte tauscht Dateien aus und verändert den Inhalt von anderen Dateien. Das Ganze sieht ungefähr so aus:
Delphi-Quellcode:
GetMD5(datei1);
GetMD5(datei2);
ErsetzeDateiMitAnderer(datei1, datei2); //=Copyfile
Öffne(datei3);
Ersetze(MD5String1 mit MD5String2 in gesamter Datei);//=direktes Schreiben mittels TStream
Schließe(datei3);
Dies Ganze wird circa 15 mal wiederholt, da 15 Dateien getauscht werden müssen und Einträge in datei3 entsprechend geändert werden müssen.

Beim Ersetzen der MD5-Hashes in datei3 wird bitweise vorgegangen, daher dauert dies etwas.

Mein eigentliches Problem ist: Die gesamte Prozedur dauert selbst auf guten Rechnern um die 2 Minuten, eindeutig zu lang.

Jetzt wäre meine Frage wie man dies beschleunigen könnte. Würden Threads etwas bringen? Jedes Mal muss in Datei3 geschrieben werden, es handelt sich hier also nur um eine Datei. Kann ich von 15 Threads aus auf eine Datei zugreifen und diese ändern? Welche anderen Möglichkeiten würde es geben, den Vorgang zu beschleunigen?

Besten Dank

Angel4585 9. Sep 2009 09:17

Re: Prozedur beschleunigen / Threads?
 
Ich würde einen Thread amchen der in die Datei schreibt und x Threads die die anderen Dateien untersuchen.
die x Threads schieben dann die Informationen die dieser eine Threads braucht in eine Liste welche dieser wiederum abarbeitet.

schlecki 9. Sep 2009 09:35

Re: Prozedur beschleunigen / Threads?
 
ev. kann man auch erstmal die 15 Dateien ändern und alles für die Datei3 vormerken und auf einmal erledigen?

himitsu 9. Sep 2009 09:42

Re: Prozedur beschleunigen / Threads?
 
hierbei Threads :shock:
Seid ihr irre?
Gleichzeitiges Schreiben/Lesen auf einem Datenträger (wenn es nicht grad eine SSD ist) würde alles wohl eher noch verschlimmern.

- erstmal schauen was so langsam ist
- wie groß sind die Dateien?
- man kann es höchstens verlagern

z.B.

Code:
Öffne(datei3); > in TMemoryStream laden
Loop:
  GetMD5(datei1);
  GetMD5(datei2);
  ErsetzeDateiMitAnderer(datei1, datei2);
  Ersetze(MD5String1 mit MD5String2 in gesamter Datei);
wiederhole Loop;
Schließe(datei3); > den MemoryStream speichern

das Ersetzen der MD5-Werte könnte man parallel zur Bearbeitung (hasching)
der jeweils Nächsten in einem Thread machen
> der Thread für die Festplatte und der für den RAM (TMemoryStream) würden sich weniger gegenseitig stören


mach ich z.B. in meinem SSF so, da läuft ein Thread durch die Liste und fragt einen anderen Thread nach den MD5s von Dateien (dieser führt eine Art Stack mit allen Dateien, die er bekommt und arbeitet sie nacheinander ab und dann gibt es noch den Hauptthread für die GUI ... parktisch immer nur ein Thread für den Datenträger und ein/mehrere Threads für Berechnungen im RAM)

[edit]
man, hab ich langsam geschrieben ... im Prinzip hat schlecki recht und das ist auch der erstmal einfachste Optimierungsweg

was noch ginge, wäre alle MD5s zu merken und sie am Ende in einem Durchgang zu ersetzen.

und ansonsten halt erstmal schauen was so langsam ist ... wie gesagt, threads sind hier eigentlich nicht wirklich sinnvoll und machen nur mehr arbeit, selbst wenn sie sogestaltet sind, daß sie sich nicht gegenseitig behindern.

taaktaak 9. Sep 2009 09:59

Re: Prozedur beschleunigen / Threads?
 
Zitat:

hierbei Threads
Seid ihr irre?
Gut formuliert!
Genau das richtige Schmankerl für einen lauen Bürotag!
:mrgreen:

Balu der Bär 9. Sep 2009 10:37

Re: Prozedur beschleunigen / Threads?
 
Danke für eure Ideen!

Zitat:

Zitat von schlecki
ev. kann man auch erstmal die 15 Dateien ändern und alles für die Datei3 vormerken und auf einmal erledigen?

Für den Austausch der Dateien brauche ich die MD5-Hashes nicht. Die sind nur zum Verändern der Datei3 notwendig.

Würde es nun wirklich etwas ausmachen wenn ich erst alle Dateien austausche und dann alles nacheinander in Datei3 schreibe? Kommt das nicht aufs Gleiche raus?

Ihr würdet also einem weiteren Thread tendieren, im Hauptthread wird Datei3 verändert und im zweiten Thread die Dateien ausgetauscht?

himitsu 9. Sep 2009 10:52

Re: Prozedur beschleunigen / Threads?
 
Zitat:

Zitat von Balu der Bär
Ihr würdet also einem weiteren Thread tendieren, im Hauptthread wird Datei3 verändert und im zweiten Thread die Dateien ausgetauscht?

neee, ich würde erstmal schauen was so langsam ist und dieses versuchen zu beschleunigen
und dann über alternativen, wie z.B. Threads, nachdenken.

also nochmal ... wie groß sind die Dateien
und wie werden sie derzeit verarbeitet?

Balu der Bär 9. Sep 2009 10:58

Re: Prozedur beschleunigen / Threads?
 
Sorry, glatt überlesen.

Die Dateien die andere ersetzen sind maximal 1 MB groß. Ich kopiere die alten Dateien (als Backup) und kopiere dann die neuen Dateien an die alte Stelle (mittels CopyFile).

Die Datei3, in welche geschrieben wird, ist maximal 100KB groß. Diese lade ich in einen TStream und ersetze Bit für Bit den MD5-Hash der alten Datei mit dem Hash der neuen Datei.

Luckie 9. Sep 2009 11:06

Re: Prozedur beschleunigen / Threads?
 
Bit für Bit? Geht das überhaupt? Aber du weißt doch, wie lang dein Hash ist, dan nkannst du ihn doch in einem Block ersetzen. Warum zeigst du uns nicht endlich mal deinen Code?

Balu der Bär 9. Sep 2009 11:11

Re: Prozedur beschleunigen / Threads?
 
Delphi-Quellcode:
procedure TXYZ.Replace(File1: TStream; oldmd5, newmd5: MD5Digest);
var
  i: Integer;
  pos: Int64;
  pattern: MD5Digest;
begin
  File1.Position := 0;
  while (File1.size - File1.position) >= sizeof(MD5Digest) do
  begin
    pos := File1.Position;
    File1.readbuffer(pattern, sizeof(MD5Digest));
    File1.position := pos + 1;
    if (comparemem(@pattern[0], @oldmd5[0], sizeof(MD5Digest))) then
    begin
      File1.position := pos;
      File1.writeBuffer(newmd5, sizeof(MD5Digest));
      break;
    end;
  end;
end;

himitsu 9. Sep 2009 11:22

Re: Prozedur beschleunigen / Threads?
 
Delphi-Quellcode:
var StreamH, Stream1, Stream2: TMemoryStream;
  i: Integer;

StreamH.LoadFromFile('Datei3');
Schleife
  Stream1.LoadFromFile('Datei1');
  Stream2.LoadFromFile('Datei2');
  Hash1 := GetMD5(Stream1);
  Hash2 := GetMD5(Stream2);
  Stream1.SaveToFile('Backup');
  Stream2.SaveToFile('Datei1');
  //for i := 0 to StreamH.Size - SizeOf(Hash) do
  //  if CompareMem(@Hash1, PAnsiChar(StreamH.Memory) + i, SizeOf(Hash)) then
  //    MoveMemory(@Hash2, PAnsiChar(StreamH.Memory) + i, SizeOf(Hash));
  i := 0;
  while i <= StreamH.Size - SizeOf(Hash) do
    if CompareMem(@Hash1, PAnsiChar(StreamH.Memory) + i, SizeOf(Hash)) then begin
      MoveMemory(@Hash2, PAnsiChar(StreamH.Memory) + i, SizeOf(Hash));
      Inc(i, SizeOf(Hash));
    end else Inc(i);
Wiederhole
StreamH.SaveToStream('Datei3');
so wären die Lese-/Schreiboperationen auf den Datenträger minimiert

[add]
Bit für Bit hatte ich eher als Byte für Byte verstanden

Delphi-Laie 9. Sep 2009 11:51

Re: Prozedur beschleunigen / Threads?
 
Zitat:

Zitat von Balu der Bär
Beim Ersetzen der MD5-Hashes in datei3 wird bitweise vorgegangen, daher dauert dies etwas.

Mein eigentliches Problem ist: Die gesamte Prozedur dauert selbst auf guten Rechnern um die 2 Minuten, eindeutig zu lang.

Und ersteres dürfte ein, wenn nicht der entscheidende Grund für letzteres sein.

Aus den guten alten Turbo-Pascal-Zeiten nahm ich die Erfahrung mit, daß sich durch Austausch von bitweisen Lese-/Schreiboperationen durch die Funktionen blockread und blockwrite (Blöcke natürlich möglichst, aber nicht über Gebühr groß wählen) der Dateizugriff wesentlich beschleunigen läßt. Delphi als TP-Erbe bietet solche Befehle weiterhin an.

himitsu 9. Sep 2009 12:10

Re: Prozedur beschleunigen / Threads?
 
Das Problem ist ja nicht unbedingt der byteweise Fortschritt, sondern mehr, daß je Byte ab diesem SizeOf(MD5)-Bytes ERNEUT eingelesen werden ... also Dateigröße*SizeOf(MD5) Bytes eingelesen und verglichen werden, wobei man hätte auch mehrere Gruppen, bzw. hier sogar Alles hätte EINMAL einlesen können und dann darin den Vergleich vornehmen.


z.B. pattern um 1000 Byte vergrößern und dann die nächsten bis zu 1000 Vergleiche direkt darin.

jfheins 9. Sep 2009 13:27

Re: Prozedur beschleunigen / Threads?
 
Ich habe so eine Funktion schonmal gesehen :stupid:

Bevor ich als indirekter Autor dieser Codebremse bezichtigt werde, möchte ich mal diese Funktion in den Raum werfen:
Delphi-Quellcode:
procedure ReplaceFile(FileName: String; old, new: Array of MD5Digest)
var
  fs: TFileStream;
  mem: TmemoryStream;
  i: Integer;
begin

  mem := TMemoryStream.Create();

  fs := TFileStream.Create(FileName, fmOpenReadWrite or fmShareExclusive);
  try
    mem.CopyFrom(fs, 0);
   
    for i = low(old) to high(old) do
    begin
      Replace(mem, old[i], new[i]);
    end;
   
    fs.CopyFrom(mem, 0);
   
  finally
    fs.Free;
    mem.Free;
  end;
end;
Bin nicht sicher ob die compiliert, aber
1. Wir statt der Datei ein Memorystream genommen, was den Vorgang beschleunigen dürfte
2. Wird die Datei nur einmal geöffnet, gelesen und nach den ganzen Ersetzungen gespeichert.

Aber vor einem Jahr hieß es doch noch "Brauche ich nicht: Performance egal, Hauptsache es läuft :) " :gruebel:

gammatester 9. Sep 2009 14:31

Re: Prozedur beschleunigen / Threads?
 
Seid ihr sicher, daß Disk-IO die Bremse ist? Ich habe eher das Suchen im Verdacht. Auf jeden Fall ist das "Suchen und Ersetzen" sehr sehr suboptimal :wink: gelöst: Geh an die erste Position und teste, wenn's nix war dann gehe halt an die nächste. Es gibt doch wesentlich besserere Such-Algorithmen (Stichwort zB Boyer-Moore u.ä.), wahrscheinlich schon in der RTL.

Gammatester

himitsu 9. Sep 2009 14:57

Re: Prozedur beschleunigen / Threads?
 
Du duchst Er sucht ja mit massig Disk-I/O :zwinker:

Ständiges hin-und-herspringen in der Datei und auch noch immer wieder winzige Stückchen lesen.

jfheins 9. Sep 2009 15:12

Re: Prozedur beschleunigen / Threads?
 
Wenn man das im Speicher auf nem Memorystream macht, sollte es ja halb so wild sein :stupid:

Da schreibt man die Prozedur extra vielseitig fpr TStream und dann kommen solche Klagen ... :?

gammatester 9. Sep 2009 15:14

Re: Prozedur beschleunigen / Threads?
 
Zitat:

Zitat von himitsu
Du duchst ja mit massig Disk-I/O :zwinker:

Ständiges hin-und-herspringen in der Datei und auch noch immer wieder winzige Stückchen lesen.

duchst??

Meinst Du mich mit dem Beitrag? Wer sagt denn, daß man ständig hin-und-herspringen muß in der Datei. Vor gefühlten 100 Jahren gab's da schon mal von Turbopower eine sauschnelle OpClone-Unit, die das mit Boyer-Moore gemacht hat, damals mit (default) 4KB-Puffer. Könnte man heute wahrscheinlich locker mit 4MB machen.

Gammatester

himitsu 9. Sep 2009 15:36

Re: Prozedur beschleunigen / Threads?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von gammatester
duchst??

Eine Taste nach links. :zwinker:
Und stimmt, es müßte "er sucht" heißen. :oops:

Nja, im Prinzip gibt es da was in meinem himXML (so als offene Quelle),
da wird auch Stückchenweise gelesen und ein Überhang mitgenommen, wenn der Suchtext über den Puffer hinausgeht.



Oder die einfache Version in diesem uralten Projekt.
halt nee, da isses doch nicht drin, aber zumindestens wird da nicht ständig zurückgesprungen

[add]
also quasi

Delphi-Quellcode:
// suchen
Schleife:
  lese Puffer (z.B. 64 KB) // direkt hinter den alten Pufferstring
                            // (der unten kopierte Teil)
  suche in Puffer
  kopiere letze Length(Suchmuster)-1 Bytes nach vorne
wiederhole

// suchen + ersetzen
Schleife:
  lese Puffer (z.B. 64 KB) // direkt hinter den alten Pufferstring
                            // (der unten kopierte Teil)
  Schleife2:
    suche in Puffer
    wenn gefunden, dann ersetzte
  wiederhole
  wenn etwas ersetzt wurde, dann speicher den Puffer
  kopiere letze Length(Suchmuster)-1 Bytes nach vorne
wiederhole


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:08 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