Nacrti u Lui

A suprogram Sličan je niti, radi se o izvedbenoj liniji sa vlastitim hrpom, vlastitim lokalnim varijablama i vlastitim pokazivačem za upute, ali s posebnošću da dijeli globalne varijable i bilo koji drugi element s ostalim korutinama.

No moramo pojasniti da postoje razlike između niti i korutine, glavna razlika je u tome što program koji koristi niti pokreće te istodobno, korutine s druge strane, oni su kolaborativni, gdje program koji koristi suprograme pokreće samo jednu od njih, a obustava ovih postiže se samo ako se to izričito traži.

The korutine Izuzetno su moćni, da vidimo što ovaj koncept obuhvaća i kako ih možemo koristiti u našim programima.

Osnovni koncepti


Sve funkcije povezane sa suprogramima u Lua nalaze se u tablici korutina, gdje je funkcija stvoriti () dopušta nam da ih stvorimo, ima jednostavan argument i funkcija je sa kodom koji će se pokrenuti suprogram, gdje je njegov povrat vrijednost vrste niti, koja predstavlja novu suprogram. Čak je i argument za stvaranje suprograma ponekad anonimna funkcija kao u sljedećem primjeru:
 co = coroutine.create (function () print ("Hello Solvetic") end)
A suprogram može imati četiri različita stanja:
  • suspendiran
  • u žurbi
  • mrtav
  • normalan

Kad ga stvorimo, počinje u stanju prekinuta, što znači da se suprogram ne pokreće automatski kada se prvi put stvori. Status korutine može se provjeriti na sljedeći način:

 ispis (coroutine.status (co))
Gdje bismo mogli pokrenuti našu korutinu, moramo koristiti samo funkciju sažima (), što ono što radi interno mijenja svoj status iz suspendiranog u trčanje.
 coroutine.resume (co)
Ako spojimo sav svoj kôd i dodamo dodatni redak za upit o dodatnom statusu naše korutine nakon što to učinimo sažima možemo vidjeti sva stanja kroz koja prolazi:
 co = coroutine.create (function () print ("Hello Solvetic") end) print (co) print (coroutine.status (co)) coroutine.resume (co) print (coroutine.status (co))
Idemo na naš terminal i izvodimo naš primjer, da vidimo rezultat našeg programa:
 lua coroutines1.lua thread: 0x210d880 Ovješen Hello Hello Solvetic dead
Kao što možemo vidjeti prvi dojam korutine je vrijednost niti, tada imamo stanje suspendiran, i to je u redu jer je ovo prvo stanje pri stvaranju, a zatim s sažima Pokrećemo suprogram s kojim ispisuje poruku i nakon toga njegov status je mrtavpošto je ispunila svoju misiju.

Korutine se na prvi pogled mogu činiti kao kompliciran način pozivanja funkcija, no one su mnogo složenije od toga. Snaga istih počiva u velikom dijelu funkcije prinos () koja dopušta obustavu pokrenute korutine kako bi kasnije nastavila s radom, pogledajmo primjer korištenja ove funkcije:

 co = coroutine.create (function () for i = 1,10 do print ("sažimajući coroutine", i) coroutine.yield () end end) coroutine.resume (co) coroutine.resume (co) coroutine.resume (co) suprogram .resume (co)
Ova će funkcija raditi do prvog prinos, i bez obzira na to imamo li ciklus za, ispisat će se samo prema toliko sažima Idemo za našu zajedničku rutinu, za kraj da vidimo izlaz kroz terminal:
 lua korutine 1. lua 1 2 3 4
Ovo bi bio izlaz kroz terminal.

Filtri


Jedan od najjasnijih primjera koji objašnjavaju korutine je slučaj potrošač Y generator informacija. Pretpostavimo tada da imamo funkciju koja kontinuirano generira neke vrijednosti čitanjem datoteke, a zatim imamo drugu funkciju koja ih čita, pogledajmo ilustrativni primjer kako bi te funkcije mogle izgledati:
 generator funkcija () dok je true radi lokalni x = io.read () šalje (x) kraj kraj funkcija potrošač () dok je istina radi lokalni x = prima () io.write (x, "\ n") kraj kraj
U ovom primjeru i potrošač i generator rade bez ikakvog odmora i možemo ih zaustaviti kada nema više informacija za obradu, međutim problem je ovdje kako sinkronizirati funkcije Poslati() Y primiti (), budući da svaki od njih ima svoju petlju, a za drugu se pretpostavlja da je usluga koju je moguće pozvati.

No s suprogramima se ovaj problem može riješiti brzo i jednostavno, pomoću dvostruke funkcije životopis / prinos možemo učiniti da naše funkcije rade bez problema. Kad suprogram pozove funkciju prinos, ne ulazi u novu funkciju, već vraća poziv koji je na čekanju i koji iz tog stanja može izaći samo pomoću nastavka.

Slično i prilikom poziva sažima ne pokreće ni novu funkciju, vraća poziv na čekanje na prinos, sažimajući ovaj proces je jedan koji nam je potreban za sinkronizaciju funkcija Poslati() Y primiti (). Primjenom ove operacije morali bismo se poslužiti primiti () Primijeni sažima do generatora za generiranje novih informacija, a zatim Poslati() primijeniti prinos Za potrošače, da vidimo kako naše funkcije izgledaju s novim promjenama:

 function receive () lokalni status, value = coroutine.resume (generator) povratna vrijednost end function send (x) coroutine.yield (x) end gen = coroutine.create (function () dok je true do local x = io.read () poslati (x) kraj kraja)
No, još uvijek možemo dodatno poboljšati naš program, a to je pomoću filteri, koji su zadaci koji istovremeno funkcioniraju kao generatori i potrošači čineći vrlo zanimljiv proces transformacije informacija.

A filtar mogu sažima iz generatora da biste dobili nove vrijednosti, a zatim primijenite prinos za pretvaranje podataka za potrošača. Pogledajmo kako možemo lako dodati filtre u naš prethodni primjer:

 gen = generator () fil = filter (gen) potrošač (fil)
Kao što vidimo, bilo je krajnje jednostavno, gdje smo osim optimizacije našeg programa stekli bodove u čitljivosti, važne za buduće održavanje.

Programi kao iteratori


Jedan od najjasnijih primjera generatora / potrošača je iteratori prisutni u rekurzivnim ciklusima, gdje iterator generira informacije koje će tijelo potrošiti unutar rekurzivnog ciklusa, pa ne bi bilo nerazumno koristiti suprograme za pisanje ovih iteratora, čak i korutine imaju poseban alat za ovaj zadatak.

Za ilustraciju načina na koji možemo koristiti korutine, napisat ćemo iterator za generiranje permutacija zadanog niza, odnosno, postaviti svaki element niza na posljednju poziciju i okrenuti ga, a zatim rekurzivno generirati sve permutacije preostalih elemenata, da vidimo kako će naš izvorna funkcija bila bi bez uključivanja korutina:

 funkcija print_result (var) za i = 1, #var do io.write (var [i], "") kraj io.write ("\ n") kraj
Ono što sada radimo je da potpuno promijenimo ovaj proces, prvo promijenimo print_result () po prinosu, da vidimo promjenu:
 funkcija permgen (var1, var2) var2 = var2 ili # var1 ako je var2 <= 1 tada coroutine.yield (var1) else
Ovo je ilustrativan primjer koji pokazuje kako iteratori rade Lua pruža nam funkciju tzv zamotati koji je sličan stvoritiMeđutim, ne vraća suprogram, vraća funkciju koja, kada se pozove, sažima suprogram. Zatim koristiti zamotati trebali bismo koristiti samo sljedeće:
 funkcija permutacije (var) povratak coroutine.wrap (function () permgen (var) kraj) kraj
Obično je ova funkcija mnogo lakša za korištenje nego stvoriti, budući da nam daje upravo ono što nam treba, što je sažetak, međutim manje je fleksibilno jer nam ne dopušta provjeru statusa suprograma stvorenog pomoću zamotati.

Korutine u Lua Oni su iznimno moćan alat za rješavanje svega vezanog uz procese koji se moraju izvesti ruku pod ruku, ali čekajući dovršenje onoga tko daje informacije, mogli smo vidjeti i njihovu uporabu za rješavanje složenih problema u vezi s procesima generatora / potrošača te optimiziranje konstrukcije iteratora u našim programima.

wave wave wave wave wave