![]() |
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:
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.
GetMD5(datei1);
GetMD5(datei2); ErsetzeDateiMitAnderer(datei1, datei2); //=Copyfile Öffne(datei3); Ersetze(MD5String1 mit MD5String2 in gesamter Datei);//=direktes Schreiben mittels TStream Schließe(datei3); 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 |
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. |
Re: Prozedur beschleunigen / Threads?
ev. kann man auch erstmal die 15 Dateien ändern und alles für die Datei3 vormerken und auf einmal erledigen?
|
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. |
Re: Prozedur beschleunigen / Threads?
Zitat:
Genau das richtige Schmankerl für einen lauen Bürotag! :mrgreen: |
Re: Prozedur beschleunigen / Threads?
Danke für eure Ideen!
Zitat:
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? |
Re: Prozedur beschleunigen / Threads?
Zitat:
und dann über alternativen, wie z.B. Threads, nachdenken. also nochmal ... wie groß sind die Dateien und wie werden sie derzeit verarbeitet? |
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. |
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?
|
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; |
Re: Prozedur beschleunigen / Threads?
Delphi-Quellcode:
so wären die Lese-/Schreiboperationen auf den Datenträger minimiert
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'); [add] Bit für Bit hatte ich eher als Byte für Byte verstanden |
Re: Prozedur beschleunigen / Threads?
Zitat:
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. |
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. |
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:
Bin nicht sicher ob die compiliert, aber
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; 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: |
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 |
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. |
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 ... :? |
Re: Prozedur beschleunigen / Threads?
Zitat:
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 |
Re: Prozedur beschleunigen / Threads?
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
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 08:43 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz