See on minu järgmine testprojekt, et näha, milline Delphi lõimeraamatukogu sobiks mulle kõige paremini minu "failide skannimise" ülesande jaoks, mida ma sooviksin töödelda mitme lõimega / lõimekogumis.
Minu eesmärgi kordamine: muutke minu 500–2000 faili järjestikune „skannimine“ keermestamata lähenemisviisist keermestatud versiooniks. Mul ei tohiks korraga olla 500 niiti, seega sooviksin kasutada lõimede kogumit. Niitkogum on järjekorda meenutav klass, mis toidab mitmeid jooksvaid lõime, mille järjekorrast järgmine ülesanne tuleb.
Esimene (väga lihtne) katse tehti lihtsalt TThread klassi laiendamise ja Execute meetodi (minu keermestatud stringi parser) juurutamisega.
Kuna Delphil ei ole lõimebasseini klassi, mis oleks karbist välja viidud, olen oma teisel katsel proovinud Primoz Gabrijelcici OmniThreadLibrary kasutamist.
OTL on fantastiline, sellel on ziljoni viisi ülesande täitmiseks taustal, kuidas minna, kui soovite oma koodi tükkide keermestatud täitmise käsitsemiseks "tule ja unusta" lähenemist.
AsyncCalls, autor Andreas Hausladen
Märkus. Alljärgnevat oleks lihtsam järgida, kui laadite lähtekoodi esmakordselt alla.
Uurides rohkem võimalusi mõne oma funktsiooni keermestatud täitmiseks, otsustasin proovida ka Andreas Hausladeni välja töötatud ühikut "AsyncCalls.pas". Andy omad AsyncCalls - asünkroonsed funktsioonikõned üksus on veel üks raamatukogu, mida Delphi arendaja saab kasutada, et leevendada keermestatud lähenemisviisi rakendamist mõne koodi käivitamisel.
Andy blogist: AsyncCallsi abil saate käivitada mitu funktsiooni korraga ja sünkroonida neid funktsiooni või meetodi igas punktis, mis neid käivitas... AsyncCallsi seade pakub mitmesuguseid funktsioonide prototüüpe asünkroonsete funktsioonide kutsumiseks. See rakendab keermefondi! Installimine on ülilihtne: kasutage lihtsalt ükskõik millise üksuse asünkrohve ja teil on kohene juurdepääs sellistele asjadele nagu "käivitage eraldi lõimes, sünkroonige peamine kasutajaliides, oodake, kuni olete valmis".
Lisaks tasuta kasutamisele (MPL-litsentsile) AsyncCalls avaldab Andy sageli ka oma parandusi Delphi IDE jaoks nagu "Delphi kiirendab"ja"DDevExtensions"Olen kindel, et olete kuulnud (kui te seda juba ei kasuta).
AsyncCalls in Action
Sisuliselt tagavad kõik AsyncCall-funktsioonid IAsyncCall-liidese, mis võimaldab funktsioone sünkroonida. IAsnycCall tutvustab järgmisi meetodeid:
//v 2,98 saidist asynccalls.pas
IAsyncCall = liides
// ootab kuni funktsioon on lõpule viidud ja tagastab tagasiväärtuse
funktsioon Sünkrooni: täisarv;
// tagastab väärtuse True, kui asünkroonifunktsioon on lõppenud
funktsioon Lõpetatud: Boolean;
// tagastab asünkroonifunktsiooni tagasiväärtuse, kui Lõpetatud on TÕES
funktsioon ReturnValue: täisarv;
// ütleb AsyncCallsile, et määratud funktsiooni ei tohi praeguses ohus täita
protseduur ForceDifferentThread;
lõpp;
Siin on kaks kutset meetodile, mis ootab kahte täisarvu parameetrit (tagastades IAsyncCall):
TAsyncCalls. Kutsu (AsyncMethod, i, juhuslik (500));
funktsiooni TAsyncCallsForm. AsyncMethod (ülesande nrr, uneaeg: täisarv): täisarv;
alustada
tulemus: = sleepTime;
Sleep (uniTime);
TAsyncCalls. VCLInvoke (
protseduur
alustada
Logi (vormindamine ('tehtud> nr:% d / ülesanded:% d / magatud:% d', [tasknr, asyncHelper. TaskCount, sleepTime]));
lõpp);
lõpp;
TAsyncCalls. VCLInvoke on viis sünkroonimiseks teie peamise lõimega (rakenduse peamine teema - teie rakenduse kasutajaliides). VCLInvoke naaseb kohe. Anonüümset meetodit hakatakse põhilõimes täitma. Seal on ka VCLSync, mis naaseb, kui peamises lõimes kutsuti anonüümset meetodit.
Keermebassein AsyncCallsis
Tagasi minu "faili skannimise" ülesande juurde: asyccallsi keermekogu söötmisel (a-silmuses) TAsyncCalls-seeriaga. Invoke () kõned, ülesanded lisatakse kogumi sisemusse ja need täidetakse "kui aeg saabub" (kui varem lisatud kõned on lõpule jõudnud).
Oodake, kuni kõik IAsyncCalls lõpule jõuavad
Asnycalls-is määratletud funktsioon AsyncMultiSync ootab asynci kõnede (ja muude käepidemete) lõppemist. Neid on vähe ülekoormatud kuidas AsyncMultiSynciks helistada, ja siin on kõige lihtsam:
funktsiooni AsyncMultiSync (const Loend: massiiv IAsyncCall; WaitAll: tõeväärtus = tõsi; Millisekundid: kardinal = INFINITE): kardinal;
Kui soovin, et "kõik ootaks" rakendamist, tuleb täita massiiv IAsyncCall ja teha AsyncMultiSync viiludena 61.
Minu AsnycCalls Helper
Siin on üks osa TAsyncCallsHelperist:
HOIATUS: osaline kood! (täielik kood on allalaadimiseks saadaval)
kasutab AsyncCalls;
tüüp
TIAsyncCallArray = massiiv IAsyncCall;
TIAsyncCallArrays = massiiv TIAsyncCallArray;
TAsyncCallsHelper = klass
privaatne
fTasks: TIAsyncCallArrays;
vara Ülesanded: TIAsyncCallArrays loe fTasks;
avalik
protseduur AddTask (const kõne: IAsyncCall);
protseduur WaitAll;
lõpp;
HOIATUS: osaline kood!
protseduur TAsyncCallsHelper. WaitAll;
var
i: täisarv;
alustada
jaoks i: = kõrge (ülesanded) alla Madal (ülesanded) teha
alustada
AsyncCalls. AsyncMultiSync (ülesanded [i]);
lõpp;
lõpp;
Nii saan "oodata kõiki" tükkides 61 (MAXIMUM_ASYNC_WAIT_OBJECTS) - st oodata IAsyncCall-i massiive.
Ülaltooduga näeb minu põhikood lõimebasseini söötmiseks välja järgmine:
protseduur TAsyncCallsForm.btnAddTasksClick (Saatja: TObject);
const
nr üksused = 200;
var
i: täisarv;
alustada
asyncHelper. MaxThreads: = 2 * süsteem. CPUCi arv;
ClearLog ('alustades');
jaoks i: = 1 kuni nr üksused teha
alustada
asyncHelper. AddTask (TAsyncCalls. Kutsu (AsyncMethod, i, juhuslik (500));
lõpp;
Logi ('kõik sisse');
// oota kõik
//asyncHelper.WaitAll;
// või lubage kõigi tühistamata jätmiste tühistamine, klõpsates nupul "Tühista kõik":
samas EI asyncHelper. Kõik viimistletud teha Rakendus. Protsessisõnumid;
Logi ('valmis');
lõpp;
Kas tühistada kõik? - Peab muutma AsyncCalls.pas :(
Samuti sooviksin leida võimaluse "tühistada" need ülesanded, mis asuvad basseinis, kuid ootavad nende täitmist.
Kahjuks ei paku AsyncCalls.pas lihtsat viisi ülesande tühistamiseks, kui see on lõimekogumisse lisatud. IAsyncCall pole. Tühista või IAsyncCall. DontDoIfNotAl jauExecuting või IAsyncCall. NeverMindMe.
Selle toimimiseks pidin muutma AsyncCalls.pas, proovides seda muuta võimalikult vähe - nii et kui Andy väljastab uue versiooni, pean oma "Tühista ülesande" idee saamiseks lisama ainult mõned read töötavad.
Ma tegin järgmist: lisasin IAsyncCallile protseduuri katkestamise. Tühistamise protseduur seab välja "FCancelled" (lisatud), mis kontrollitakse, kui bassein hakkab ülesannet täitma. Ma pidin IAsyncCall-i pisut muutma. Lõpetatud (nii et kõneraportid lõpetatakse ka siis, kui need katkestatakse) ja TAsyncCall. InternExecuteAsyncCall protseduur (kõnet mitte teostada, kui see on tühistatud).
Sa võid kasutada WinMerge Andy originaalse asynccall.pas ja minu muudetud versiooni (lisatud allalaaditavas versioonis) erinevuste hõlpsaks leidmiseks.
Võite alla laadida kogu lähtekoodi ja uurida.
Ülestunnistamine
TEADE! :)
Tühista kutse meetod peatab AsyncCall'i kutsumise. Kui AsyncCall on juba töödeldud, siis üleskutse CancelInvocation'ile ei toimi ja tühistatud funktsioon tagastab vale, kuna AsyncCall ei olnud tühistatud.
Tühistatud meetod tagastab väärtuse True, kui AsyncCall tühistati CancelInvocationi abil.
Unustage meetod eraldab IAsyncCalli liidese sisemisest AsyncCallist. See tähendab, et kui viimane viide IAsyncCall-liidesele on kadunud, siis asünkroonkõne ikkagi teostatakse. Liidese meetodid muudavad erandi, kui pärast Unustaja kutsumist sellele helistatakse. Asünkroonimisfunktsioon ei tohi põhilõime sisse kutsuda, kuna seda saaks käivitada pärast TT-lõiku. Sünkroonimise / järjekorra mehhanism sulges RTL, mis võib põhjustada surnud luku.
Pange siiski tähele, et saate siiski minu AsyncCallsHelperist kasu saada, kui peate ootama, kuni kõik asünkroonikõned lõpevad "asyncHelperiga". WaitAll "; või kui teil on vaja "CancelAll".