Primer baze navojev Delphi z uporabo AsyncCalls

click fraud protection

To je moj naslednji testni projekt, da vidim, katera knjižnica navojev za Delphi bi mi najbolj ustrezala za mojo nalogo "skeniranja datotek", ki bi jo rad obdelal v več niti / v področju niti.

Če želite ponoviti svoj cilj: spremenite moje zaporedno "skeniranje datotek" 500-2000 + datotek iz ne-navojanega pristopa v navojeno. Ne bi smel naenkrat teči 500 niti, zato bi želel uporabiti obseg niti. Povezava niti je razred podoben vrsti, ki napaja številne tekoče niti z naslednjo nalogo iz čakalne vrste.

Prvi (zelo osnovni) poskus je bil narejen s preprostim podaljšanjem razreda TThread in izvajanjem metode Execute (moj razdelilnik nitnih nizov).

Ker Delphi nima razreda baze navojev, ki se izvaja zunaj polja, sem v drugem poskusu poskusil z OmniThreadLibrary Primoza Gabrijelčiča.

OTL je fantastičen, ima na milijone načinov za izvajanje naloge v ozadju, pot, če želite imeti "ognje in pozabi" pristop za izročanje navoženih izvedb kosov vaše kode.

AsyncCalls Andreas Hausladen

Opomba: Naslednje bi bilo lažje slediti, če najprej naložite izvorno kodo.
instagram viewer

Medtem ko sem raziskal več načinov izvajanja nekaterih funkcij na nitni način, sem se odločil poskusiti tudi z enoto "AsyncCalls.pas", ki jo je razvil Andreas Hausladen. Andyjevih AsyncCalls - Asinhroni klici funkcij enota je še ena knjižnica, ki jo lahko razvijalec Delphi olajša bolečino pri izvajanju nitnega pristopa k izvajanju neke kode.

Iz bloga Andy: Z AsyncCalls lahko hkrati izvajate več funkcij in jih sinhronizirate na vsaki točki funkcije ali metode, ki jih je začel... Enota AsyncCalls ponuja številne prototipe funkcij za klicanje asinhronih funkcij... Izvaja bazen z nitmi! Namestitev je zelo enostavna: uporabite samo asynccalls iz katere koli svoje enote in imate takojšen dostop do stvari, kot so "izvedite v ločeni niti, sinhronizirajte glavni uporabniški vmesnik, počakajte, da končate".

Poleg brezplačne uporabe (licenca MPL) AsyncCalls, Andy pogosto objavlja tudi svoje popravke za Delphi IDE, kot je "Delphi pospeši"in"DDevExtensions"Prepričan sem, da ste že slišali (če že ne uporabljate).

AsyncCalls v akciji

V bistvu vse funkcije AsyncCall vrnejo vmesnik IAsyncCall, ki omogoča sinhronizacijo funkcij. IAsnycCall izpostavlja naslednje metode:

 //v 2,98 od asynccalls.pas
IAsyncCall = vmesnik
// počaka, da se funkcija konča in vrne vrnjeno vrednost
funkcija Sync: Integer;
// vrne True, ko je funkcija asinhrone končana
funkcija končana: Boolean;
// vrne povratno vrednost funkcije asinhrone, ko je Finished TRUE
funkcija ReturnValue: Integer;
// pove AsyncCalls, da dodeljena funkcija ne sme biti izvršena v trenutni nevarnosti
postopek ForceDifferentThread;
konec;

Tu je primer klica metode, ki pričakuje dva parametra celih števil (vrne IAsyncCall):

 TAsyncCalls. Pokliči (AsyncMethod, i, Random (500));
funkcijo Obrazec TAsyncCalls. AsyncMethod (taskNr, sleepTime: integer): celo število;
začeti
rezultat: = čas spanja;
Spanje (čas mirovanja);
TAsyncCalls. VCLInvoke (
postopek
začeti
Dnevnik (Oblika ('opravljeno> nr:% d / opravila:% d / spal:% d', [tasknr, asyncHelper). Opravilni račun, čas spanja]));
konec);
konec;

TAsyncCalls. VCLInvoke je način za sinhronizacijo z vašo glavno nitjo (glavna nit aplikacije - uporabniški vmesnik vaše aplikacije). VCLInvoke se takoj vrne. Anonimna metoda se izvede v glavni niti. Obstaja tudi VCLSync, ki se vrne, ko je bila v glavni nit poklicana anonimna metoda.

Navojni bazen v AsyncCalls

Nazaj na mojo nalogo "skeniranja datotek": ko hranite (v zanki), niz nit asynccalls z nizom TAsyncCalls. Pokliči () klice, naloge bodo dodane v notranji bazen in se bodo izvajale ", ko pride čas" (ko so že dodani klici končani).

Počakajte, da se vsi IAsyncCalls končajo

Funkcija AsyncMultiSync, definirana v asnyccalls, čaka, da se končajo klici async (in drugi ročaji). Kar nekaj jih je preobremenjen načini za klic AsyncMultiSync in tukaj je najenostavnejši:

funkcijo AsyncMultiSync (konst Seznam: niz od IAsyncCall; WaitAll: Boolean = Res; Milisekunde: kardinal = INFINITE): kardinal; 

Če želim izvesti "čakati vse", moram izpolniti niz IAsyncCall in AsyncMultiSync narediti v rezinah 61.

Moj pomočnik AsnycCalls

Tukaj je del TAsyncCallsHelperja:

OPOZORILO: delna koda! (za prenos je na voljo celotna koda)
uporablja AsyncCalls;
tip
TIAsyncCallArray = niz od IAsyncCall;
TIAsyncCallArrays = niz od TIAsyncCallArray;
TAsyncCallsHelper = razred
zasebno
fTasks: TIAsyncCallArrays;
premoženje Naloge: TIAsyncCallArrays prebrati fTasks;
javnosti
postopek AddTask (konst klic: IAsyncCall);
postopek Počakajte vse;
konec;
OPOZORILO: delna koda!
postopek TAsyncCallsHelper. Počakajte vse;
var
i: celo število;
začeti
za i: = visoko (naloge) downto Nizka (naloge) stori
začeti
AsyncCalls. AsyncMultiSync (Naloge [i]);
konec;
konec;

Tako lahko "čakam vse" v kosih 61 (MAXIMUM_ASYNC_WAIT_OBJECTS) - tj. Čakam na matrike IAsyncCall.

Z zgoraj navedenim je moja glavna koda za napajanje baze niti videti:

postopek TAsyncCallsForm.btnAddTasksClick (Pošiljatelj: TObject);
konst
nrItems = 200;
var
i: celo število;
začeti
asyncHelper. MaxThreads: = 2 * sistem. CPUCount;
ClearLog ('zagon');
za i: = 1 do nrItems stori
začeti
asyncHelper. AddTask (TAsyncCalls). Pokliči (AsyncMethod, i, Random (500)));
konec;
Prijava ("vse v");
// počakajte vse
//asyncHelper.WaitAll;
// ali dovolite preklic vsega, kar se ni začelo, s klikom na gumb "Prekliči vse":

medtem, ko NE asyncHelper. Vse dokončano stori Uporaba. ProcessMessages;
Dnevnik ('končano');
konec;

Prekliči vse? - Spremeniti morate AsyncCalls.pas :(

Prav tako bi želel, da bi "opravili" tiste naloge, ki so v bazenu, a čakajo na njihovo izvedbo.

Na žalost AsyncCalls.pas ne ponuja enostavnega načina preklica naloge, ko je dodan v niz niti. IAsyncCall ni. Prekliči ali IAsyncCall. DontDoIfNotAlreadyExecuting ali IAsyncCall. NeverMindMe.

Da bi to delovalo, sem moral spremeniti AsyncCalls.pas tako, da sem ga poskušal čim manj spremeniti - torej da ko Andy izda novo različico, moram dodati le nekaj vrstic, da imam svojo idejo »Prekliči nalogo« delujoč.

Tukaj sem naredil: IAsyncCall sem dodal "Prekliči postopek". Postopek preklica nastavi polje "FCancegled" (dodano), ki se preveri, ko se bazen začne izvajati nalogo. Moral sem nekoliko spremeniti IAsyncCall. Končano (tako da so poročila o klicu končana tudi ob preklicu) in TAsyncCall. InternExecuteAsyncCall postopek (ne izvede klica, če je bil preklican).

Lahko uporabiš WinMerge za enostavno iskanje razlik med Andyjevim originalnim asynccall.pas in mojo spremenjeno različico (vključeno v prenos).

Lahko prenesete celotno izvorno kodo in raziščete.

Spoved

OPAZITI! :)

The Prekliči poziv metoda ustavi poziv AsyncCall. Če je AsyncCall že obdelan, klic na CancelInvocation nima nobenega učinka in preklicana funkcija bo vrnila False, saj AsyncCall ni bil preklican.
The Prekinjeno metoda vrne True, če je AsyncCall preklical CancelInvocation.
The Pozabi metoda odklopi vmesnik IAsyncCall od notranjega AsyncCall. To pomeni, da če ne bo zadnjega sklicevanja na vmesnik IAsyncCall, bo asinhroni klic še vedno izveden. Metode vmesnika bodo vrgle izjemo, če ga pokličemo po klicu Pozabi. Funkcija asinhronizacije ne sme klicati v glavno nit, ker se lahko izvede po TThread-u. RTL je zaustavil mehanizem za sinhronizacijo / čakalno vrsto, kar lahko povzroči mrtvo zaklepanje.

Upoštevajte pa, da lahko še vedno izkoristite moj AsyncCallsHelper, če boste morali počakati, da se vsi klici async končajo z "asyncHelper. Počakajte vse "; ali če morate "Prekliči".

instagram story viewer