„Delphi“ gijų baseino pavyzdys naudojant „AsyncCalls“

Tai yra kitas mano bandomasis projektas, norint pamatyti, kokia „Delphi“ sriegių biblioteka man labiausiai tiktų „failų nuskaitymo“ užduočiai, kurią norėčiau apdoroti keliose gijose / gijų baseine.

Norėdami pakartoti savo tikslą: paverskite mano nuoseklų 500–2000 failų „nuskaitymą“ iš ne srieginio požiūrio į srieginį. Aš neturėčiau turėti 500 gijų vienu metu, todėl norėčiau naudoti gijų fondą. Sriegių fondas yra eilę primenanti klasė, teikianti daugybę bėgimo gijų su kita užduotimi iš eilės.

Pirmasis (labai paprastas) bandymas buvo tiesiog praplečiant „TThread“ klasę ir įgyvendinant „Execute“ metodą (mano srieginių eilučių analizatorius).

Kadangi „Delphi“ nėra gijų telkinio klasės, įdiegtos iš dėžutės, antruoju bandymu bandžiau naudoti „OmniThreadLibrary“, kurią sukūrė Primozas Gabrijelcicas.

OTL yra fantastiškas, turi milijardus būdų, kaip vykdyti užduotį fone, kelią, kurį norite naudoti, jei norite turėti „ugnį ir pamiršk“ požiūrį, kai reikia atlikti srieginį kodo įvykdymą.

„AsyncCalls“ pateikė Andreas Hausladenas

instagram viewer
Pastaba: tai, kas aprašyta toliau, bus lengviau sekti, jei pirmą kartą atsisiuntėte šaltinio kodą.

Tyrinėdamas daugiau būdų, kaip tam tikras mano funkcijas vykdyti sriegiais, nusprendžiau išbandyti ir Andreas Hausladeno sukurtą padalinį „AsyncCalls.pas“. Andy's „AsyncCalls“ - asinchroniniai funkcijos skambučiai skyrius yra dar viena biblioteka, kurią „Delphi“ kūrėjas gali naudoti, kad palengvintų srieginio požiūrio į kai kurio kodo vykdymą skausmą.

Iš Andy tinklaraščio: Naudodami „AsyncCalls“ galite vienu metu vykdyti kelias funkcijas ir sinchronizuoti jas kiekviename funkcijos ar metodo taške, kuris jas paleido... „AsyncCalls“ vienetas siūlo įvairius funkcijų prototipus, skirtus asinchroninėms funkcijoms iškviesti... Tai įgyvendina siūlų fondą! Įdiegti yra labai paprasta: tereikia naudoti asynccalls iš bet kurio savo įrenginio ir turite tiesioginę prieigą prie tokių dalykų kaip „vykdykite atskirame gijoje, sinchronizuokite pagrindinę vartotojo sąsają, palaukite, kol baigsite“.

Be laisvai naudojamo (MPL licencijos) „AsyncCalls“, Andy taip pat dažnai skelbia savo „Delphi IDE“ pataisas, pavyzdžiui, „„Delphi Speed ​​Up“"ir"„DDevExtensions“"Aš tikiu, kad esate girdėję apie (jei dar nesinaudojate).

„AsyncCalls“ veikia

Iš esmės visos „AsyncCall“ funkcijos grąžina „IAsyncCall“ sąsają, leidžiančią sinchronizuoti funkcijas. „IAsnycCall“ atskleidžia šiuos metodus:

 //v 2.98 iš asynccalls.pas
IAsyncCall = sąsaja
// laukia, kol funkcija bus baigta, ir grąžins grąžinimo vertę
funkcija Sinchronizuoti: Sveikasis skaičius;
// grąžina True, kai asinchroninio įrenginio funkcija baigta
funkcija baigta: Boolean;
// grąžina asinchroninės funkcijos grąžinimo vertę, kai Baigta yra TIESA
funkcija ReturnValue: Sveikasis skaičius;
// nurodo AsyncCalls, kad paskirta funkcija neturi būti vykdoma esant dabartinei grėsmei
procedūra ForceDifferentThread;
galas;

Štai pavyzdys, kaip reikia iškviesti metodą, laukiantį dviejų sveikųjų skaičių parametrų (grąžinti „IAsyncCall“):

 TAsyncalls. Iškviesti („AsyncMethod“, „i“, „Random“ (500));
funkcija „TAsyncCallsForm“. „AsyncMethod“ (užduoties Nr., Miego laikas: sveikasis skaičius): sveikasis skaičius;
prasideda
rezultatas: = miego laikas;
Miegas (sleepTime);
TAsyncalls. VCLInvoke (
procedūra
prasideda
Žurnalas (Formatas ('atlikta> nr:% d / užduotys:% d / miegota:% d', [tasknr, asyncHelper. „TaskCount“, „sleepTime“]));
galas);
galas;

„TAsyncCalls“. „VCLInvoke“ yra būdas sinchronizuoti su jūsų pagrindine gija (pagrindinis programos gija - jūsų programos vartotojo sąsaja). VCLInvoke iškart grįžta. Anoniminis metodas bus vykdomas pagrindinėje gijoje. Taip pat yra „VCLSync“, kuris grįžta, kai pagrindinėje gijoje buvo iškviestas anoniminis metodas.

Sriegių baseinas „AsyncCalls“

Grįžti prie mano „failų nuskaitymo“ užduoties: kai tiekiate asinccalls sriegių grupę su „TAsyncCalls“ serija. Iškvieskite () skambučius, užduotys bus įtrauktos į bendrą telkinį ir bus įvykdytos „kai ateis laikas“ (kai anksčiau baigti skambučiai bus baigti).

Palaukite, kol visi „IAsyncCalls“ bus baigti

AsyncMultiSync funkcija, apibrėžta asnyccalls, laukia, kol bus baigti async skambučiai (ir kitos rankenos). Yra keli perkrautas būdus, kaip paskambinti „AsyncMultiSync“, ir štai paprasčiausias:

funkcija „AsyncMultiSync“ (const Sąrašas: masyvas „IAsyncCall“; „WaitAll“: loginė = teisinga; Milisekundės: kardinolas = INFINITE): kardinolas; 

Jei noriu, kad „laukiu visų“ būtų įgyvendinta, turiu užpildyti „IAsyncCall“ rinkinį ir atlikti „AsyncMultiSync“ 61 pjūviu.

„My AsnycCalls Helper“

Štai „TAsyncCallsHelper“ dalis:

ĮSPĖJIMAS: dalinis kodas! (pilną kodą galima atsisiųsti)
naudoja AsyncCalls;
tipo
TIAsyncCallArray = masyvas „IAsyncCall“;
TIAsyncCallArrays = masyvas „TIAsyncCallArray“;
TAsyncCallsHelper = klasė
privatus
„fTasks“: „TIAsyncCallArrays“;
nuosavybė Uždaviniai: TIAsyncCallArrays skaityti fTasks;
viešai
procedūra „AddTask“ (const skambutis: IAsyncCall);
procedūra Laukti visko;
galas;
ĮSPĖJIMAS: dalinis kodas!
procedūra TAsyncCallsHelper. Laukti visko;
var
i: sveikasis skaičius;
prasideda
dėl i: = aukštas (užduotys) žemyn Žemas (užduotys) daryti
prasideda
„AsyncCalls“. „AsyncMultiSync“ (užduotys [i]);
galas;
galas;

Tokiu būdu galiu „laukti visų“ 61 vieneto vienetu (MAXIMUM_ASYNC_WAIT_OBJECTS) - t.y. laukti „IAsyncCall“ masyvų.

Remiantis tuo, kas išdėstyta aukščiau, mano pagrindinis kodas, skirtas maitinti siūlų fondą, atrodo taip:

procedūra TAsyncCallsForm.btnAddTasksClick (Siuntėjas: TObject);
const
nr Prekės = 200;
var
i: sveikasis skaičius;
prasideda
„asyncHelper“. „MaxThreads“ = 2 * sistema. CPUC skaičius;
„ClearLog“ ('pradedant');
dėl i: = nuo 1 iki nr daryti
prasideda
„asyncHelper“. „AddTask“ („TAsyncCalls“. Iškviesti („AsyncMethod“, „i“, „Random“ (500)));
galas;
Žurnalas ('visi in');
// laukti visi
//asyncHelper.WaitAll;
// arba leiskite atšaukti visus nepradėtus, spustelėdami mygtuką „Atšaukti viską“:

tuo tarpu NE „asyncHelper“. Viskas baigta daryti Taikymas. Proceso pranešimai;
Žurnalas ('baigtas');
galas;

Atšaukti visus? - Privalote pakeisti „AsyncCalls.pas“ :(

Taip pat norėčiau būdo, kaip „atšaukti“ tas užduotis, kurios yra baseine, bet laukia jų vykdymo.

Deja, AsyncCalls.pas nepateikia paprasto būdo, kaip atšaukti užduotį, kai ji bus įtraukta į gijų fondą. Nėra „IAsyncCall“. Atšaukti arba „IAsyncCall“. „DontDoIfNotAlreadyExecuting“ arba „IAsyncCall“. „NeverMindMe“.

Kad tai veiktų, aš turėjau pakeisti AsyncCalls.pas bandydamas jį pakeisti kuo mažiau - taigi kad kai Andy išleis naują versiją, turiu pridėti tik keletą eilučių, kad turėčiau savo mintį „Atšaukti užduotį“ dirbantys.

Štai ką aš padariau: „IAsyncCall“ pridėjau „procedūros atšaukimą“. Atšaukimo procedūra nustato lauką „FCancelled“ (pridėta), kuris patikrinamas, kai baseinas pradeda vykdyti užduotį. Man reikėjo šiek tiek pakeisti „IAsyncCall“. Baigta (kad skambučio ataskaitos būtų baigtos net atšaukus) ir „TAsyncCall“. InternExecuteAsyncCall procedūra (nevykdyti skambučio, jei jis buvo atšauktas).

Tu gali naudoti „WinMerge“ kad lengvai rastumėte skirtumus tarp originalios Andy asynccall.pas ir mano pakeistos versijos (įtraukta į atsisiuntimą).

Galite atsisiųsti visą šaltinio kodą ir tyrinėti.

Išpažintis

PASTEBĖTI! :)

 Atšaukti kvietimą metodas sustabdo AsyncCall paleidimą. Jei „AsyncCall“ jau apdorotas, skambutis „CancelInvocation“ neturi jokios įtakos ir atšaukta funkcija grįš netiesa, nes „AsyncCall“ nebuvo atšaukta.
Atšauktas metodas grįžta tiesą, jei „AsyncCall“ buvo atšauktas „CancelInvocation“.
Pamiršk metodas atsieja „IAsyncCall“ sąsają nuo vidinės „AsyncCall“. Tai reiškia, kad jei paskutinės nuorodos į „IAsyncCall“ sąsają nebeliks, asinchroninis skambutis vis tiek bus vykdomas. Sąsajos metodai sukels išimtį, jei paskambins po „Pamiršti“. Async funkcija neturi įsitraukti į pagrindinę giją, nes ją buvo galima vykdyti po TThread. RTL uždarė sinchronizavimo / eilės mechanizmą, kuris gali sukelti negyvą užraktą.

Tačiau atminkite, kad vis tiek galite gauti naudos iš „AsyncCallsHelper“, jei reikia laukti, kol visi asinchroniniai skambučiai baigsis „asyncHelper“. WaitAll “; arba jei jums reikia „CancelAll“.