Tämä on seuraava testiprojektini nähdäkseni, mikä Delphin lankakirjasto sopisi minulle parhaiten "tiedostojen skannauksen" tehtäväksi, jonka haluaisin käsitellä useissa ketjuissa / ketjuvarannossa.
Toistan tavoitteeni: Muunna 500–2000 tiedostoa sisältävä peräkkäinen tiedostojen skannaus kierteettömästä lähestymistavasta kierteitetyksi. Minulla ei pitäisi olla 500 säiettä käynnissä kerralla, joten haluaisin käyttää säieallasta. Lankapooli on jonon kaltainen luokka, joka syöttää useita juoksevia ketjuja seuraavalla tehtävällä jonosta.
Ensimmäinen (hyvin perustason) yritys tehtiin yksinkertaisesti laajentamalla TThread-luokkaa ja toteuttamalla Execute-menetelmä (kierteistetyn merkkijonojen jäsennin).
Koska Delphillä ei ole säiepohjaluokkaa, joka olisi toteutettu laatikosta, olen yrittänyt toisessa yrityksessäni käyttää Primoz Gabrijelcicin OmniThreadLibrary-ohjelmaa.
OTL on fantastinen, sillä on lukemattomia tapoja suorittaa tehtävä taustalla, tapa edetä, jos haluat "palo ja unohda" -lähestymistavan käsitellä koodin kierrettyjä suorituksia.
AsyncCalls kirjoittanut Andreas Hausladen
Huomaa: Seuraava on helpompi seurata, jos lataat lähdekoodin ensin.
Tutkiessani lisää tapoja suorittaa joitain toiminnoista kierteitetyllä tavalla olen päättänyt kokeilla myös Andreas Hausladenin kehittämää "AsyncCalls.pas" -yksikköä. Andyn AsyncCalls - Asynkroniset toimintopuhelut yksikkö on toinen kirjasto, jota Delphi-kehittäjä voi käyttää lievittääkseen kipua kierteitetyn lähestymistavan toteuttamisessa jonkin koodin suorittamiseen.
Andyn blogi: AsyncCalls -sovelluksella voit suorittaa useita toimintoja samanaikaisesti ja synkronoida ne jokaisessa toiminnon tai menetelmän kohdassa, joka aloitti ne... AsyncCalls-yksikkö tarjoaa erilaisia toimintoprototyyppejä kutsumaan asynkronisia toimintoja... Se toteuttaa säiealtaan! Asennus on erittäin helppoa: käytä vain minkä tahansa yksiköidesi asynkallioita ja sinulla on välitön pääsy esimerkiksi "suorita erillisessä säikeessä, synkronoi pääkäyttöliittymä, odota, kunnes se on valmis".
Vapaasti käytettävän (MPL-lisenssin) AsyncCalls -sovelluksen lisäksi Andy julkaisee usein myös omia korjauksiaan Delphi IDE: lle, kuten "Delphi Speed Up"ja"DDevExtensions"Olen varma, että olet kuullut (jos et käytä jo).
AsyncCalls toiminnassa
Pohjimmiltaan kaikki AsyncCall-toiminnot palauttavat IAsyncCall-käyttöliittymän, joka mahdollistaa toimintojen synkronoinnin. IAsnycCall paljastaa seuraavat menetelmät:
//v 2,98 asynccalls.pas: sta
IAsyncCall = käyttöliittymä
// odottaa, kunnes toiminto on valmis ja palauttaa palautusarvon
toiminto Synkronointi: kokonaisluku;
// palauttaa True, kun asynkronitoiminto on valmis
toiminto valmis: Boolean;
// palauttaa asynkronitoiminnon paluuarvon, kun Valmis on TOSI
toiminto ReturnValue: kokonaisluku;
// sanoo AsyncCallsille, että määritettyä toimintoa ei tule suorittaa nykyisessä uhkassa
menettely ForceDifferentThread;
end;
Tässä on esimerkki puhelusta menetelmälle, joka odottaa kahta kokonaislukuparametria (palauttaa IAsyncCall):
TAsyncCalls. Kutsu (AsyncMethod, i, Random (500));
toimia TAsyncCallsForm. AsyncMethod (tehtäväNr, uni aika: kokonaisluku): kokonaisluku;
alkaa
tulos: = sleepTime;
Sleep (sleepTime);
TAsyncCalls. VCLInvoke (
menettely
alkaa
Loki (Muoto ('valmis> ei:% d / tehtävät:% d / nukkui:% d', [tasknr, asyncHelper. TaskCount, sleepTime]));
pää);
pää;
TAsyncCalls. VCLInvoke on tapa synkronoida pääsäikeesi kanssa (sovelluksen pääläie - sovelluksen käyttöliittymä). VCLInvoke palaa välittömästi. Nimetön menetelmä suoritetaan pääkierteessä. Siellä on myös VCLSync, joka palaa, kun pääketjuun kutsuttiin nimettömää menetelmää.
Kiertoallas AsyncCallsissa
Takaisin "tiedostojen skannaus" -tehtäväni: kun syötetään asyccalls-säiealustaa TAsyncCalls-sarjoilla (a-silmukassa). Kutsu () -puhelut, tehtävät lisätään sisäiseen pooliin ja ne suoritetaan "kun aika tulee" (kun aiemmin lisätyt puhelut ovat päättyneet).
Odota kaikki IAsyncCalls loppuun
Asnycalls-sovelluksissa määritetty AsyncMultiSync-toiminto odottaa async-kutsujen (ja muiden kahvojen) päättymistä. Niitä on muutama ylikuormittunut tapoja soittaa AsyncMultiSync, ja tässä on yksinkertaisin:
toimia AsyncMultiSync (const Lista: joukko IAsyncCall; WaitAll: Boolen = totta; Millisekuntia: kardinaali = INFINITE): kardinaali;
Jos haluan, että "odota kaikki" toteutetaan, minun on täytettävä joukko IAsyncCall-sovelluksia ja tehtävä AsyncMultiSync 61-viipaleina.
Oma AsnycCalls-auttajani
Tässä on pala TAsyncCallsHelperistä:
VAROITUS: osittainen koodi! (täydellinen koodi ladattavissa)
käyttötarkoitukset AsyncCalls;
tyyppi
TIAsyncCallArray = joukko IAsyncCall;
TIAsyncCallArrays = joukko TIAsyncCallArray;
TAsyncCallsHelper = luokka
yksityinen
fTasks: TIAsyncCallArrays;
omaisuus Tehtävät: TIAsyncCallArrays lukea fTasks;
julkinen
menettely AddTask (const puhelu: IAsyncCall);
menettely WaitAll;
pää;
VAROITUS: osittainen koodi!
menettely TAsyncCallsHelper. WaitAll;
var
i: kokonaisluku;
alkaa
varten i: = korkea (tehtävät) downto Alhainen (tehtävät) tehdä
alkaa
AsyncCalls. AsyncMultiSync (Tehtävät [i]);
pää;
pää;
Tällä tavalla voin "odottaa kaikkia" kappaleina 61 (MAXIMUM_ASYNC_WAIT_OBJECTS) - ts. Odottaa IAsyncCall-ryhmiä.
Edellä esitetyllä tavalla pääkoodini säiealustan syöttämiseksi näyttää seuraavalta:
menettely TAsyncCallsForm.btnAddTasksClick (Lähettäjä: TObject);
const
nro = 200;
var
i: kokonaisluku;
alkaa
asyncHelper. MaxThreads: = 2 * järjestelmä. CPUCount;
ClearLog ( 'alkaa');
varten i: = 1 kohtaan nr tehdä
alkaa
asyncHelper. AddTask (TAsyncCalls. Kutsu (AsyncMethod, i, Random (500));
pää;
Loki ('kaikki sisään');
// odota kaikki
//asyncHelper.WaitAll;
// tai salli kaikkien aloittamattomien peruuttaminen napsauttamalla Peruuta-painiketta:
vaikka EI asyncHelper. AllFinished tehdä Sovellus. ProcessMessages;
Log ( 'valmis');
pää;
Peruuta kaikki? - Joudut vaihtamaan AsyncCalls.pas :(
Haluaisin myös tavan "peruuttaa" ne tehtävät, jotka ovat altaassa, mutta odottavat niiden suorittamista.
Valitettavasti AsyncCalls.pas ei tarjoa yksinkertaista tapaa peruuttaa tehtävä, kun se on lisätty ketjuvarantoon. IAsyncCallia ei ole. Peruuta tai IAsyncCall. DontDoIfNotAlreadyExecuting tai IAsyncCall. Älä välitä minusta.
Jotta tämä toimisi, minun piti muuttaa AsyncCalls.pas yrittämällä muuttaa sitä mahdollisimman vähän - niin että kun Andy julkaisee uuden version, minun on lisättävä vain muutama rivi saadakseni "Peruuta tehtävä" -ideani työ.
Näin tein: Olen lisännyt "menettelyn peruuttamisen" IAsyncCall-sovellukseen. Peruutusmenettely asettaa "FCancelled" (lisätty) -kentän, joka tarkistetaan, kun uima-allas on alkamassa suorittaa tehtävää. Minun piti muuttaa IAsyncCall-ohjelmaa hieman. Valmis (niin, että puheluraportit valmistuivat jopa peruutettaessa) ja TAsyncCall. InternExecuteAsyncCall-menettely (ei suorittaa puhelua, jos se on peruutettu).
Voit käyttää WinMerge löytääksesi helposti eroja Andyn alkuperäisen asynccall.pas -sovelluksen ja muutetun version (sisältyy lataukseen) välillä.
Voit ladata kokonaisen lähdekoodin ja tutkia.
Tunnustus
ILMOITUS! :)
CancelInvocation menetelmä estää AsyncCall-sovelluksen käynnistämisen. Jos AsyncCall on jo käsitelty, kutsuun CancelInvocation ei ole vaikutusta ja peruutettu toiminto palaa vääriksi, koska AsyncCallia ei peruutettu.
peruttu menetelmä palaa totta, jos AsyncCall peruutettiin CancelInvocation -sovelluksella.
Unohtaa menetelmä poistaa IAsyncCall-liittymän sisäisestä AsyncCallista. Tämä tarkoittaa, että jos viimeinen viittaus IAsyncCall-rajapintaan on poissa, asynkroninen puhelu suoritetaan edelleen. Rajapinnan menetelmät heittävät poikkeuksen, jos niitä kutsutaan Unohtamisen soittamisen jälkeen. Async-toiminto ei saa kutsua pääketjuun, koska se voitiin suorittaa TThreadin jälkeen. RTL sulki synkronointi- / jono-mekanismin, mikä voi aiheuttaa kuollut lukituksen.
Huomaa kuitenkin, että voit silti hyötyä AsyncCallsHelper -sovelluksesta, jos joudut odottamaan kaikkien async-puheluiden päättymistä asyncHelper-sovelluksella. WaitAll "; tai jos sinun on "Peruuta kaikki".