![]() |
ThreadPool 1.0.9 für Delphi 2010-XE
Nachdem ich vergeblich nach einem Open-Source Thread-Pool für Delphi gesucht habe, welches meine Bedürfnisse abdeckt, musste ich mich dafür entschließen, einen eigenen zu schreiben. Diesen möchte ich euch hier vorstellen.
Vereinfacht kann man die Funktionsweise des ThreadPools wie folgt beschreiben: Man verbindet sich aus einem beliebigen Thread mit dem spezifischen Manager (welcher ebenfalls ein eigenständiger Thread ist) und übergibt ihm eine Aufgabe. Der Manager übergibt die Aufgabe an einen neuen bzw. schlafenden Arbeiter oder packt sie auf die Warteliste, wenn bestimmte Grenzwerte es nicht zulassen die Aufgabe sofort abzuarbeiten. Der Arbeiter nimmt sich der Aufgabe an, arbeitet sie parallel ab und meldet sich über synchronisierte Ereignisse, wenn er fertig ist. Hat der Manager noch weitere Aufgaben anliegen, so bekommt der Arbeiter sofort den Nächsten. Sind alle Aufträge abgearbeitet, so kann der Manager eine bestimmte anzahl an Arbeitern schlafen legen (SpareWorkersCount) und die restlichen Arbeiter werden terminiert. Hauptmerkmale
Download Damit ich das Archiv nicht bei jedem Update hier aktualisieren muss, verlinke ich am liebsten zur Projektseite bei SourceForge: ![]() ![]() ![]() Das Archiv enthält bereits zwei ausführliche Beispiele (auch in kompilierter Form), sodass man sowohl die Implementierung eines spezialisierten Thread-Pools nachvollziehen kann als auch dessen Verwendung. Voraussetzung Die Unit ist ab Delphi 2010 lauffähig. Lizenz Wie ich in der Einleitung geschrieben hatte, suchte ich nach einer Open-Source Lösung, die es nicht gab. Aus diesem Grunde stelle ich meine unter die MPL 1.1. mfg |
AW: Abstrakter ThreadPool
Ich habe mal versucht deine Beispiele zu kompilieren. Leider lässt sich ThreadPool unter meinem Delphi 2009 (alle aktuellen Updates eingespielt) nicht kompilieren.
Hier die Fehlermeldungen:
Code:
[DCC Fehler] ThreadPool.pas(183): E2123 PROCEDURE, FUNCTION, PROPERTY oder VAR erwartet
[DCC Fehler] ThreadPool.pas(184): E2169 Felddefinition nicht erlaubt nach Methoden oder Eigenschaften [DCC Warnung] ThreadPool.pas(184): W1010 Methode 'Destroy' verbirgt virtuelle Methode vom Basistyp 'TThread' [DCC Fehler] ThreadPool.pas(188): E2254 Die überladene Prozedur 'Create' muss mit der Direktive 'overload' gekennzeichnet sein [DCC Fehler] ThreadPool.pas(189): E2254 Die überladene Prozedur 'Destroy' muss mit der Direktive 'overload' gekennzeichnet sein [DCC Fehler] ThreadPool.pas(191): E2252 Es gibt bereits eine Methode 'Destroy' mit identischen Parametern [DCC Fehler] ThreadPool.pas(390): E2123 PROCEDURE, FUNCTION, PROPERTY oder VAR erwartet [DCC Warnung] ThreadPool.pas(390): W1010 Methode 'Destroy' verbirgt virtuelle Methode vom Basistyp 'TPoolThread' [DCC Fehler] ThreadPool.pas(481): E2254 Die überladene Prozedur 'Destroy' muss mit der Direktive 'overload' gekennzeichnet sein [DCC Fehler] ThreadPool.pas(483): E2252 Es gibt bereits eine Methode 'Destroy' mit identischen Parametern [DCC Fehler] ThreadPool.pas(563): E2357 PROCEDURE, FUNCTION oder CONSTRUCTOR erwartet [DCC Fehler] ThreadPool.pas(568): E2357 PROCEDURE, FUNCTION oder CONSTRUCTOR erwartet [DCC Fehler] ThreadPool.pas(574): E2004 Bezeichner redefiniert: 'TPoolThread.Create' [DCC Fehler] ThreadPool.pas(581): E2004 Bezeichner redefiniert: 'TPoolThread.Destroy' [DCC Fehler] ThreadPool.pas(931): E2357 PROCEDURE, FUNCTION oder CONSTRUCTOR erwartet [DCC Fehler] ThreadPool.pas(971): E2004 Bezeichner redefiniert: 'TPoolManager.Destroy' [DCC Fehler] ThreadPool.pas(972): E2004 Bezeichner redefiniert: 'cc' [DCC Fehler] ThreadPool.pas(183): E2065 Ungenügende Forward- oder External-Deklaration: 'TPoolThread.Create' [DCC Fehler] ThreadPool.pas(184): E2065 Ungenügende Forward- oder External-Deklaration: 'TPoolThread.Destroy' [DCC Fehler] ThreadPool.pas(390): E2065 Ungenügende Forward- oder External-Deklaration: 'TPoolManager.Destroy' [DCC Fataler Fehler] PrimePoolForm.pas(6): F2063 Verwendete Unit '..\..\ThreadPool.pas' kann nicht compiliert werden |
AW: Abstrakter ThreadPool
Zitat:
Delphi-Quellcode:
Oder die Unterstützung der Generics (benutze massiv Generics.Collections.TObjectList) ist noch schlechter als in 2010.TPoolThread = class(TThread) type // verschachtelte Typen deklaration TLockList = TObjectList<TMultiReadExclusiveWriteSynchronizer>; TCriticalSectionList = TObjectList<TCriticalSection>; private public ... end; Ich persönlich bin von 2007 gleich auf 2010 gesprungen und habe nie 2009 verwendet, aber dass es Closures (anonyme Methoden) beherrscht wusste ich. Tja, dann muss ich die Anforderungen vorerst einfach mal hochschrauben. Danke für das Feedback. |
AW: Abstrakter ThreadPool
Zitat:
|
AW: Abstrakter ThreadPool
Dann müsste man aber auch auf die anonymen Methoden verzichten, von daher habe ich persönlich wenig Hoffnung :(
|
AW: Abstrakter ThreadPool
Zitat:
Wer einmal die Vorteile von Closures erkannt hat, kann nicht mehr ohne... Sorry. |
AW: Abstrakter ThreadPool
Wenn ich das richtig sehe, scheitert Delphi2009 am
Delphi-Quellcode:
bzw.
class constructor Create;
Delphi-Quellcode:
(die wohl für das Singleton-Pattern vorhanden sind?)
class destructor Destroy;
Ich habe mal testweise die Klassen-Konstruktoren und -Destruktoren auskommentiert, und sobald die vollständig gestrichen wurden, kompilierte Delphi2009 die Unit problemlos durch. Meine Erfahrungen sagen auch, dass verschachtelte Typen (in D2009) kein Problem sein sollten, da ich die schon selbst mal verwendet hatte ;) Ansonsten hört sich der ThreadPool schonmal sehr interessant an, wäre schön, wenn ich die nutzen könnte :) |
AW: Abstrakter ThreadPool
Zitat:
Ansonsten könnte man eine Compiler-Weiche einbauen und sich bei D2009 des initialization/finalization-Abschnitts bedienen. |
AW: Abstrakter ThreadPool
Laut Google sollen die Klassen-Konstruktoren erst ab Delphi2010 unterstützt werden ;)
(Aus der Fehlermeldung Zitat:
Delphi-Quellcode:
bzw.
constructor
Delphi-Quellcode:
nach einem
destructor
Delphi-Quellcode:
erwartet. Habe trotzdem mal die verschiedenen Sichtbarkeiten durchprobiert: Wie zu erwarten ohne Erfolg ;) )
class
|
AW: Abstrakter ThreadPool
Zitat:
danke für die Information (war zu faul zum googeln :wink:), werde demnächst (bin grad an was anderem dran) die erwähnte Compiler-Weiche einbauen und mich hier wieder melden. |
AW: Abstrakter ThreadPool
Habe eine ungeteste Anpassung für Delphi 2009 eingebaut und ins Repository eingespielt:
![]() Musste die bewährte "Compilers.inc" von Mike Lischke einbinden. Kann das jemand testen und mir mitteilen, ob es sich damit jetzt compilieren lässt? Dank im Voraus! |
AW: Abstrakter ThreadPool
Danke für Deine Änderungen, aber:
ThreadPool lässt sich nun ohne Fehlermeldung kompilieren. Die beiliegenden Demos stürzen jedoch ab, im folgenden die ersten Fehlermeldungen mit dem angezeigten Codeabschnitt:
Code:
->Erste Gelegenheit für Exception bei $76EDFBAE. Exception-Klasse EAccessViolation mit Meldung 'Zugriffsverletzung bei Adresse 00475AF1 in Modul 'PrimePoolProject.exe'. Lesen von Adresse 00000000'. Prozess PrimePoolProject.exe (4432)
function IsTaskValid(Task:TPoolTask):Boolean;
begin Result:=Owner.Tasks.IndexOf(Task) >= 0; end;
Code:
-> Erste Gelegenheit für Exception bei $76EDFBAE. Exception-Klasse EAccessViolation mit Meldung 'Zugriffsverletzung bei Adresse 00475AF1 in Modul 'PrimePoolProject.exe'. Lesen von Adresse 00000000'. Prozess PrimePoolProject.exe (4432)
procedure TPoolManager.WorkerTerminated(TerminatedWorker:TPoolWorker);
begin BeginWriteWorkers; try Workers.Remove(TerminatedWorker); finally EndWriteWorkers; MainSignal.SetEvent; end; end; |
AW: Abstrakter ThreadPool
Zitat:
Fragen über Fragen. Hätte ich mir doch gleich denken können, dass man für keine "Plattform" programmiert, die man selbst nicht hat/testen kann. :cry: |
AW: Abstrakter ThreadPool
Antworten
1. Der Fehler tritt erst auf wenn Add Task geklickt wird, der Fehler tritt erst am beim letzen (?) Durchlauf der Schleife for c:= 0 to Steps - 1 auf 2. Nein, im Memo werden keine Einträge angelegt 3. Die beiliegenden Kompilate der Demos laufen problemlos 4. Der Fehler tritt bei den vom mir kompilierten Demos immer auf. |
AW: Abstrakter ThreadPool
Zitat:
Generics/Closures wurden in D2010 verbessert = beta Generics/Closures wurden in DXE weiter verbessert = stable? So oder so ähnlich wird es wohl sein. Genau da vermute ich den Fehler. Daher werde ich das bisher versuchte wieder droppen und nicht weiter probieren etliche Workarounds einzubauen, um mit D2009 kompatibel zu sein. Der ganze ThreadPool sollte ursprünglich komplett auf Generics basieren, welchen man nur die spezielle Task-Klasse übergibt, doch dort scheiterte ich, weil der Support der Generics noch nicht fehlerfrei ist, damit will ich sagen, dass ich schon mit 2010er meine Probleme hatte. So ist das mit neuen Möglichkeiten, doch irgendwann muss man sie nutzen um einen Nutzen zu erlangen. Nichtsdestotrotz ist es Open Source, also wenn das jemand hinmoddeld, dass es funktioniert, dem ist ein Eintrag unter Credits/Copyrights sicher. |
Neue Version 1.0.1 herausgegeben
Soeben habe ich die neue Version 1.0.1 veröffentlicht. (Links siehe 1. Beitrag)
Neben einigen Optimierungen enthält es jetzt die Unterstützung für priorisierbare Tasks. Ableitende Tasks können die Eigenschaften TPoolTask.Priority oder TPoolTask.PriorityRaw veröffentlichen und der entsprechende Manager muss die Eigenschaft TPoolManager.SortTasks auf TRUE setzen um die Sortierung zu aktivieren. Wenn mehr Aufgaben hinzugefügt werden, als gleichzeitig abgearbeitet werden können, so kommen die Tasks mit der höheren Priorität eher dran. Ach ja, als Voraussetzung bleibt: ab Delphi 2010 :shock: |
AW: Abstrakter ThreadPool
Was vielleicht noch für den einen odere anderen nützlich sein könnte, wären Abhängigkeiten der Aufträge, so dass B erst nach A ausgeführt wird.
Prinzipiell ist die Sache super. Für mich zwar mangeld D2010/XE nicht nutzbar, aber es zeigt, dass die Community zumindest noch nich ganz kapituliert hat ;) |
AW: Abstrakter ThreadPool
Zitat:
Delphi-Quellcode:
var Task:TMyTask; begin Task:=TMyTask.Create(Owner); // Task mit Daten füllen Task.OnDone:=procedure(Sender:TObject) var DependTask:TMyTask; begin if TMyTask(Sender).State <> tsSuccess then Exit; DependTask:=TMyTask.Create(Owner); // DependTask mit Daten füllen TMyPoolManager.AddTask(DependTask); end; TMyPoolManager.AddTask(Task); end; Zitat:
![]() |
AW: Abstrakter ThreadPool
Auf die Idee mit dem Event-Handler war ich auch schon gekommen. Die Abhängigkeit mit in das Interface zu integrieren, würde weniger Glue-Code produzieren und man könnte Workflows fast 1:1 abbilden.
Natürlich wird Native-Code noch lange eine Rolle spielen. Aber IMHO werden es immer weniger Community-Projekte und 3rd-Party-Bibliotheken/Komponenten. Und schließlich waren die ganzen Projekte rund um Delphi lange ein Alleinstellungsmerkmal. |
Neue Version 1.0.3 veröffentlicht
Hallo alle zusammen,
heute habe ich die neue Version 1.0.3 des ThreadPool veröffentlicht (Download-Links wie gehabt im 1. Beitrag). Die ThreadPool-Unit wurde massiv rationalisiert. Es werden jetzt weniger Locks benötigt und die ganze Unit konnte (trotz höherer Versionsnummer) etwas schrumpfen. In der Version 1.0.2, die ich hier nicht vorstellte, gab es eine CodeSite-Integration, die mittels Compiler-Conditionals in der beiliegenden Compile.inc aktiviert werden kann. Es ist doch ziemlich schwierig soetwas mittels Breakpoints/OutputDebugString zu debuggen. Desweiteren kam ein DUnit-Testprojekt hinzu, in dem —unter anderem– diverse Stress-Tests stattfinden, die vor jedem Release bestanden werden müssen. Es ist ebenfalls dem Archiv beigelegt. Ich wünsche allen ein erfolgreiches neues Jahr! P.S.: Ja, ich bin auf Delphi XE umgestiegen und bin sehr glücklich damit :-D. Da ich D2010 parallel betreibe, ist (und hoffentlich bleibt) der ThreadPool weiterhin damit kompatibel. |
Brauche ein paar Tester
Liste der Anhänge anzeigen (Anzahl: 2)
Ein Hallo an alle DP-Mitglieder,
muss seit gestern wieder den ThreadPool erweitern und habe einige heikle Änderungen durchführen müssen. Soweit sieht es ganz gut aus, die DUnit-Tests laufen problemlos, auf meinem Core-i7 920 und in Virtual-PC (Single-Core), durch. Doch was heisst das schon...ich brauche noch ein paar Tests von anderen Systemen. Wer ist von Euch so nett und lässt den angehängten (kompilierten) Test auf seinem Rechner laufen? Wenn ihr die Exe startet, reicht ein Klick auf den grünen Play-Button (oder Enter-Taste), um einen Test-Durchlauf zu starten. Ein kompletter Durchlauf dauert, je nach System, ca. 1-3 Minuten. Jeder bestandene Teil-Test wird grün gekennzeichnet. Wichtig ist, dass es komplett grün durchläuft (wie im angehängten Screenshot). Schön wäre es auch, wenn Ihr den gesamten Test mehrmals wiederholen könntet. Drückt dazu jeweils auf Enter, wenn es fertig ist. Natürlich brauche ich dann Feedback (am besten mit Screenshot), wenn es nicht durchläuft oder gar Exceptions geworfen wurden. Aber über ein einfaches "Läuft komplett durch!", würde ich mich auch freuen. ;-) mfg P.S.: Die aktuellen Codes sind im ![]() |
AW: ThreadPool 1.0.3 für Delphi 2010-XE
Hallo,
:arrow: "Läuft komplett durch!" ;) Intel Core 2 Duo, 2,93GHz 2GB RAM Windows Vista 32-Bit Gruß Neutral General |
AW: ThreadPool 1.0.3 für Delphi 2010-XE
Zitat:
|
AW: ThreadPool 1.0.3 für Delphi 2010-XE
Hi,
drei mal laufen lassen, keine Probleme :P |
AW: ThreadPool 1.0.3 für Delphi 2010-XE
Zitat:
Da ich parallel schon zig Tests durchgeführt habe, sehe ich jetzt einfach mal die Änderungen als "stabil" an. |
AW: ThreadPool 1.0.3 für Delphi 2010-XE
Ich denke, das ist berechtigt, selbst auf meinem "vermurkten" Laptop mit Vista 32 Bit treten keine Fehler auf.
|
AW: ThreadPool 1.0.3 für Delphi 2010-XE
...3 Starts, drei mal ohne Fehler (Win 7 64 Bit, Core X5)
|
AW: ThreadPool 1.0.3 für Delphi 2010-XE
Hi,
Weils so viel Spaß gemacht hat, nochmal auf meinem Rechner zuhause, wieder ohne Probleme ;) Intel Core i5 - 2,66GHz 4GB RAM Windows 7 Professional 64 Bit |
AW: ThreadPool 1.0.3 für Delphi 2010-XE
Moin moin,
Core i7-860 2.8 GHz 8 GB RAM Windows 7 Professional x64 läuft alles 1A durch ;) |
AW: ThreadPool 1.0.3 für Delphi 2010-XE
Ein gebündeltes Dankeschön an alle Tester!
Ihr könnt euch nicht vorstellen, wie sehr mich diese Ergebnisse beruhigen und motivieren. Es ist gar nicht so einfach einen Thread-Pool ohne eine (Windows-)Message-Queue, sondern nur mit Delphi-Bordmitteln umzusetzen. Ich bin nämlich optimistisch in den kommenden Jahren diesen auf Mac und Linux laufen sehen zu können. :twisted: |
AW: ThreadPool 1.0.3 für Delphi 2010-XE
Hallo,
auch auf meinem Hightech Rechner (Pentium 4 3GHz HT ) mit Windows 7pro lief der Test ohne Probleme durch. Hat halt nur etwas gedauert :-) Torsten |
Neue Version 1.0.9 veröffentlicht
Heute habe ich die neue Version 1.0.9 veröffentlicht.
Was ich hier ehemals Vorstellte, hat sich (mal wieder) grundlegend geändert, aus diesem Grund habe ich den 1. Beitrag komplett überarbeitet (siehe oben). Diese Unit wird übrigens produktiv in ![]() Dort werden 2 spezielle Thread-Pools verwendet. Einer für sämtliche HTTP-Anfragen und ein Bild-Skalierungs-Thread-Pool :lol: |
AW: ThreadPool 1.0.9 für Delphi 2010-XE
Gibt es etwas Neues? Läuft das auch unter XE2, XE3 oder XE4?
|
AW: ThreadPool 1.0.9 für Delphi 2010-XE
Zitat:
![]() Ich denke mit Anpassung der Compilers.inc sollte es vermutlich in XE2...X4 funktionieren. |
AW: ThreadPool 1.0.9 für Delphi 2010-XE
Also es gibt nichts Neues. Hintergrund der Frage ist, dass bei uns eine Evaluierung zum Einsatz eines Threadpools stattfindet. Eine Bibliothek, die laufend gepfegt wird, hat da Pluspunkte. :)
|
AW: ThreadPool 1.0.9 für Delphi 2010-XE
Ich weiß nicht mehr wieviele Male ich mir fest vorgenommen habe mich wieder da ran zu setzen... :roll: Auch AnyiQuack und Lauge will ich irgendwann mal wieder auf Vordermann bringen. Und die Projektseiten müssten auch mal gepflegt werden.
Nach der Arbeit hab ich einfach keine Zeit/Lust mehr oder ich werde einfach zu alt. :? |
AW: ThreadPool 1.0.9 für Delphi 2010-XE
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:29 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 by Thomas Breitkreuz