Cuprins capitolul 1– Istoria sistemelor de operare 2


Avantajele si dezavantajele procedurilor stocate



Yüklə 359,7 Kb.
səhifə2/6
tarix03.11.2017
ölçüsü359,7 Kb.
#29140
1   2   3   4   5   6

2.6 Avantajele si dezavantajele procedurilor stocate

Avantajele procedurilor stocate

Unul dintre principalele avantaje ale procedurilor stocate este folosirea resurselor performante ale serverului.De obicei într-o organizaţie serverele au cele mai performante configuraţii, mult peste resursele hardware ale calculatoarelor personale. Prin folosirea procedurilor stocate,operaţiile de prelucrare a datelor se realizează pe sisteme mult mai rapide decât staţiile de lucru, ceea ce poate duce la micşorarea timpului de aşteptare a sistemului de către utilizator.

Fiecare client, atunci când apelează proceduri stocate, apelează ultima variantă a acestora, astfel că modificarea aplicaţiilor client se face mai rar, ceea ce presupune o întreţinere mai uşoară a prelucrărilor. De multe ori organizaţiile care au apelat la firme de software pentru dezvoltarea sistemelor informatice oferă posibilitatea conectării acestora la propriile servere de baze de date pentru o întreţinere mai rapidă şi pentru înţelegerea corectă a diverselor situaţii apărute. Aceste posibilităţi de conectare pot fi folosite şi pentru a modifica mai uşor modul de prelucrare a datelor.

Procedurile stocate se evidenţiază şi prin reutilizarea codului de către mai multe aplicaţii,evitându-se astfel duplicarea scrierii codului şi toate dezavantajele ce decurg din acest lucru. Interfaţa se poate schimba uşor dacă o mare parte din logica aplicaţiei este inclusă în procedurile stocate.Trecerea de la o arhitectură tradiţională client-server la o arhitectură pe niveluri se realizează mult mai simplu dacă în prima versiune a sistemului s-au folosit proceduri stocate.

Prelucrarea clasică a datelor într-o arhitectură client-server presupune transferul datelor de intrare în aplicaţia client, prelucrarea acestora şi transferul rezultatelor înapoi la serverul de baze de date. Toată această activitate implică folosirea din plin a resurselor reţelei. Prin prelucrarea datelor acolo unde sunt şi stocare se diminuează considerabil gradul de folosire a resurselor reţelei.

Procedurile stocate extind capacitatea de interogare şi de manipulare a datelor unui SGBD. De exemplu o funcţie stocată poate fi folosită în cadrul unei fraze SQL, în condiţiile în care, în toate implementările, apelul unei funcţii sau proceduri stocate este foarte simplu.

Procedurile stocate oferă, prin intermediul declanşatorilor, o posibilitate de implementare a unei politici de acces ,controlându-se cine, când, de unde şi cu ce se efectuează modificările.

În plus, procedurile stocate, scrise în SQL/PSM prezintă un avantaj în faptul că sunt uşor de înţeles de programatorii neexperimentaţi datorită simplităţii sintaxei. SQL/PSM a fost proiectat în aşa fel încât implementările să poată suporta supraîncărcarea procedurilor şi a funcţiilor. În acest fel pot exista proceduri şi/sau funcţii cu acelaşi nume, dar cu semnături diferite (care să aibă parametri diferiţi ca şi număr şi tip).

Toate tipurile de date din SQL/Foundation se regăsesc şi în SQL/PSM, ceea ce elimină o parte din problemele de transformare între diferite tipuri de date. În procedurile stocate scrise în SQL/PSM se pot folosi şi tipuri de date definite de utilizator.

Procedurile stocate în limbajele de programare generalizate au ca avantaje specifice: portabilitatea, scalabilitatea şi dezvoltarea rapidă. O procedură stocată scrisă într-un limbaj de programare poate rula, cu mici modificări, în cadrul unei aplicaţii client sau într-un server de aplicaţii. În cadrul organizaţiilor în care se implementează un sistem informatic ce foloseşte un SGBD ce suportă astfel de proceduri stocate, pot exista deja rutine scrise în limbaje de programare generalizate. O portabilitate deosebită se obţine şi între diferite SGBD-uri ce suportă aceleaşi limbaje de programare pentru scrierea procedurilor stocate.

Datorită atenţiei în implementarea maşinilor virtuale s-a reuşit să se păstreze caracteristicile de scalabilitate ale SGBD-urilor. Astfel, experimentele au demonstrat faptul că necesarul suplimentar de memorie per conexiune în cazul unor implementări Oracle este de numai 28kB, fiind deci posibilă gestiunea multor utilizatori simultan. Procedurile stocate pot fi create pe baza unor componente deja verificate, totul realizându-se în mod vizual. Testarea funcţionalităţii procedurii se poate face în cadrul unui program client, urmând ca apoi să se facă punerea în exploatare în cadrul serverului de baze de date.

În plus, în unele implementări (cum ar fi Oracle), apelul unei proceduri stocate scrise într-un limbaj de programare generalizat (Java) nu presupune lansarea în execuţie a unor noi procese.

Dezavantajele procedurilor stocate

Ca orice funcţionalitate nou apărută într-un sistem, aduce cu ea şi noi provocări de protecţie şi securitate a datelor. Pentru atacatori, procedurile stocate nu reprezintă doar noi ţinte, ci şi noi modalităţi de atacare a datelor din bazele de date. Pot exista proceduri stocate care să conţină troieni, viermi sau chiar viruşi.

Procedurile stocate nu pot conţine chiar toate restricţiile economice şi toată logica afacerii. Sunt anumite elemente care rămân de implementat în interfaţă şi care se declanşează, de exemplu, pe măsură ce utilizatorul parcurge un formular.

Centralizarea prelucrărilor pe serverul de baze de date poate aduce neplăceri atunci când execuţia uneia sau a mai multor proceduri stocate consumă cea mai mare parte din resursele serverului, iar celelalte conexiuni la baza de date îşi pierd din performanţă. Nespecificarea importanţei relative a prelucrărilor făcute de procedurile stocate duce la regula “primul venit, primul servit”, care în anumite cazuri presupune o întârziere a unor prelucrări cu o importanţă deosebită.

În cazul procedurilor stocate, scrise în SQL/PSM s-a observant în unele implementări invalidarea în cascadă a procedurilor stocate ca urmare a unor modificări în structura datelor sau ca urmare a unor invalidari ale altor proceduri stocate. Se pune astfel în discuţie una dintre regulile fundamentale ale modelului relaţional şi anume regula independenţei logice a datelor faţă de prelucrări.

Procedurilor stocate, scrise în SQL/PSM, le scade portabilitatea pe măsură ce folosesc pachetele puse la dispoziţie de SGBD-ul respectiv. Tot în cazul lor se constată o grijă în plus în ceea ce priveşte versiunile rutinelor din cadrul aceluiaşi pachet din moment ce procedurile şi funcţiile incluse nu pot fi modificate decât în acelaşi timp cu tot pachetul.

Codul sursă al procedurilor stocate scrise în SQL/PSM poate să ajungă în posesia unor persoane care nu au dreptul decât de execuţie asupra acestora. Deşi în unele implementări există posibilitatea criptării acestor proceduri stocate, au apărut şi programe care să le decripteze.

În cazul procedurilor stocate scrise într-un limbaj de programare generalizat pot apărea diferenţe între tipurile de date suportate de nucleul SQL al SBGD-ului respectiv şi tipurile de date suportate de limbajul de programare în care sunt implementate procedurile stocate.

Majoritatea avantajelor prezentate sugerează o creştere a performanţelor sistemelor ce folosesc proceduri stocate. Se subînţelege astfel că beneficiile majore ale procedurilor stocate se observă în cadrul sistemelor informatice ce folosesc baze de date mari şi care au rutine ce folosesc intens datele din bazele de date. Procedurile stocate nu excelează în schimb la algoritmi de calcul optimizaţi şi nici nu au o portabilitate deosebită dacă nu sunt scrise într-un limbaj de programare generalizat.

3. Corutinele

În ştiinţa calculatoarelor, corutinele reprezintă componente de program care generalizează subrutine pentru a permite puncte de intrare multiple pentru suspendarea şi reînceperea execuţiilor în anumite locaţii. Corutinele sunt potrivite pentru implementarea de componente de program mai familiar, precum task-uri cooperative, iteraţii, liste infinite şi pipe-uri.

Termenul de “corutină” îşi are originea în lucrarea lui Melvin Conway din anul 1963.

3.1 Corutine sau subrutine?

Corutinele sunt mult mai generice decât subrutinele. Durata de viaţă a subrutinelor este influenţată de “Last In First Out“(LIFO-ultima subrutină apelată este prima care se întoarce). În contrast, durata de viaţă a corutinelor este dictată în totalitate de utilizarea lor şi gradul de necesitate.

Începutul unei subrutine reprezintă unicul punct de intrare. Ea poate fi returnată o singură dată. În opoziţie cu aceasta, corutinele pot fi accesate de mai multe ori. Începutul unei corutine reprezintă primul punct de intrare şi următoarele puncte pot fi accesate prin comenzi de apelare. Practic, este întors rezultatul corutinei apelate, căreia i se redă controlul, asemenea unei subrutine obişnuite. Totuşi, când corutina este accesată ulterior, execuţia nu porneşte de la începutul corutinei, ci de la apelul de accesare.

Se oferă, spre exemplu, următoarea situaţie în care corutinele sunt utile. Se presupune că există o relaţie consumator-producător, unde o rutină crează produse şi le adaugă unei “cozi”, iar o altă rutină preia produsele din “coadă” şi le foloseşte. Pentru sporirea eficienţei, se doreşte adăugarea şi preluarea mai multor produse odata. Codul necesar efectuării operaţiei ar putea fi următorul:



var q := coadă nouă
corutina produce

loop

while q nu este plin

creaza produse noi

adaugă produsele la q

yield către consum

corutina consumă

loop

while q nu este gol

preia o parte din produse din q

utilizeaza produsele

yield către producere
Coada este complet plină sau golită inainte de a obţine controlul la o altă corutină, folosind comanda de acces. În continuare, apelurile de corutine încep imediat după comanda de acces, în bucla exterioară a corutinei.

3.2 Comparaţie detaliată
Întrucât corutinele au mai multe puncte de intrare şi ieşire decaât subrutinele, este posibilă implementarea oricărei subrutine ca o corutină.

”Corutinele sunt cazuri speciale de subrutine”-Donald Knuth.

De fiecare dată când este apelată o subrutină, execuţia porneşte la începutul subrutinei invocate. De asemenea, când o corutină este invocată pentru prima dată, execuţia porneşte la începutul acesteia. Totuşi, de fiecare dată când are loc invocarea corutinei, execuţia se reia imediat din locul în care corutina a fost returnată ultima dată.

O subrutină este returnată o singură dată. În opoziţie, o corutină poate fi returnată de mai multe ori, facând posibilă întoarcerea de valori adiţionale până la apeluri ulterioare ale corutinei. Astfel de corutine sunt numite adesea generatoare.

Subrutinele necesită doar o singură stivă care poate fi prealocată la începutul execuţiei programului. Corutinele, putand accesa şi alte co-rutine, se implementează cel mai bine folosind “continuări”. Acestea pot necesita alocări de stive adiţionale şi, de aceea, sunt implementate în limbaje de nivel înalt.

3.3 Corutine şi generatori

Generatorii sunt o generalizare a subrutinelor, dar cu o putere mai puţin expresivă, la prima vedere,decât cea a corutinelor. Din moment ce generatorii sunt folosiţi,de obicei, în simplificarea scrierilor de iteraţii, declaraţia de randament într-un generator nu specifică corutina la care să se facă saltul, ci mai degrabă, transmite o valoare înapoi către rutina-părinte. Totuşi, este posibilă implementarea corutinelor ca pe o facilitate de top a unui generator, cu ajutorul unei rutine-dispecer de nivel înalt care controlează explicit generatorul-copil, identificat prin “jetoane” trimise înapoi către generatori:



var q := new queue
generator produce

loop

while q is not full

create some new items

add the items to q

yield consume
generator consume

loop

while q is not empty

remove some items from q

use the items

yield produce
subroutine dispatcher

var d := new dictionarygenerator → iterator

d[produce] := start produce

d[consume] := start consume

var current := produce

loop

current := next d[current]

O serie de implementări de corutine pentru limbi de suport pentru generator folosesc acest model.



3.4 Utilizări generale ale corutinelor

Corutinele sunt folosite pentru implementarea următoarelor:



  • maşini de stare în cadrul unei singure subrutine, unde starea este determinată de punctul de intrare/ieşire curent al procedurii

  • modelul-acţiune (de exemplu: jocurile video). Fiecare “acţiune” are procedura ei, dar predă voluntar controlul unităţii centrale, care o execută secvenţial

  • generatori: sunt folosiţi pentru intrări/ieşiri şi pentru traversarea generică a structurilor de date

Limbajele de programare ce suportă corutinele sunt: Aikido, AngelScript, BETA, C#, Dynamic C, Java Script, Limbo, Lucid, Modula-2, Python,Simula-67, Squirrel,Tcl.

3.5 Alternative şi implementări de corutine

Corutinele au fost iniţial tehnici de asamblare limbaj, dar sunt folosite şi în unele limbaje de nivel înalt, cum ar fi Simula şi Modula-2, limbaje timpurii, iar mai recente, Lua şi Go.

Multe dintre limbajele de programare populare, incluzând C şi derivatele acestuia, nu au suport direct pentru corutine în librăriile lor de date.

În situaţiile în care o corutină ar fi implementarea naturală a unui mecanism, dar nu este disponibilă, actiunea logică este crearea unei subrutine ce foloseşte o asamblare ad-hoc a steagurilor boolene şi ale altor variabile pentru a menţine o stare internă între apeluri. Condiţiile din interiorul codului au ca rezultat, executarea de diferite căi de cod către apeluri succesive, bazate pe valorile variabilelor de stare. Un alt răspuns tipic este implementarea unei stări explicite a maşinii sub forma unei afirmaţii complexe şi întinsă ca mărime. Asemenea implementări sunt dificil de înţeles şi menţinut.

Fibrele reprezintă o alternativă la corutine în mediile de programare din ziua de azi. Acestea oferă facilităţi pentru manevrarea în timp real a mai multor secvenţe de cod simultan şi sunt răspândite pe scară largă în medii ce suporta C. Sunt familiare multor programatori şi sunt implementate cu uşurinţă. Totuşi, pe măsură ce rezolvă o gamă largă de probleme dificile, ele includ multe facilităti complexe şi au o curbă de învăţare dificilă. De exemplu, când este necesară doar o singură subrutină, utilizarea unei fibre poate fi dăunătoare.

O diferenţă important între fibre şi corutine este aceea că fibrele sunt programate preventiv în timp ce corutinele nu sunt. Deoarece fibrele pot fi reprogramate oricand şi pot fi executate concomitent, programele ce le folosesc trebuie să fie “atente” la blocare. În opoziţie, deoarece corutinele pot fi reprogramate doar în puncte specifice în program şi nu se execută concomitent, programele pot adesea evita blocarea în totalitate.



Implementări pentru C

Au fost făcute numeroase încercări, cu diferite grade de succes, de implementare a corutinelor în C în combinaţii de subrutine şi macro-uri.

Contribuţia lui Simon Tatham reprezintă un bun exemplu, propriile sale comentarii furnizând o bună evaluare a limitărilor abordării sale. O abordare mai solidă a implementării corutinelor în C este renunţarea la portabilitate şi scrierea de implementări specifice familiei de procesoare, în asamblare şi de funcţii pentru a salva şi restaura contextul unei rutine.

Librăria standard C include funcţii numite “setjmp” şi” longjmp”, care pot fi folosite în implementarea unor anumite forme de corutine. Dar acestea sunt dificil de implementat, iar programatorul face presupuneri minime asupra lor. Din păcate, implementările defectuoase ale acestora sunt destul de frecvente. Deoarece folosesc o singură stivă, ”setjmp” şi “longjmp” nu pot implementa natural corutine, întrucât variabilele stocate în stiva vor fi suprascrise când o altă corutină va folosi aceeaşi stivă.

În C, funcţiile sunt necesare pentru crearea şi saltul între stive alternative. O a treia funcţie care poate fi scrisă în cod C, este necesară creerii unei noi corutine. Librăriile C furnizează asemenea rutine ca “getcontext”, ”setcontext”, ”makecontext” şi “swapcontext”.

Familia “setcontext” este considerată mai puternică decât “setjmp/longjmp”, dar implementările corecte sunt foarte rare.

Principalul neajuns al acestei abordări este acela că stiva corutinei este o mărime fixă şi nu poate creşte în timpul execuţiei. De aceea, programele tind să aloce mai mult spaţiu decât au nevoie pentru a evita overflow-ul stivei.

4 Subrutine în Matlab

Presupunându-se cunoscut lucrul cu vectorii şi matricile în Matlab, uneori se doreşte repetarea unei secvenţe de comenzi, dar acest lucru să se facă prin utilizarea unor vectori şi matrici diferite.



O modalitate mai simplă de a face acest lucru este prin utilizarea subrutinelor. Subrutinele sunt la fel ca fişierele executabile, dar pot utiliza diferiţi vectori şi matrici.
De exemplu, dacă se doreşte o subrutină pentru a efectua eliminarea gaussiană, dar se vrea posibil şi lucrul cu matrici şi vectori (acest exemplu provine de la tutorial loops). Prima linie din fişier trebuie să spună programului ce variabile vor fi returnate, când şi de ce variabile e nevoie pentru a lucra. În cele ce urmează, se va încerca găsirea lui x din ecuaţia Ax = b.

Rutina necesită matricea A şi vectorul B şi va fi returnat vectorul x. Dacă numele fişierului este gaussElim.m, atunci prima linie va arăta astfel:

[function x] = gaussElim (A, B)

Dacă se vrea returnarea a mai mult de o singură variabilă, se poate include în lista cu numele variabilelor separate prin virgule, dintre paranteze (a se vedea al doilea exemplu). Pentru a scrie fişiere executabile, se utilizează tutorialul executable files.

În cele ce urmează, se va prezenta o secţiune din fişierul gaussElim.m:


function [x] = gaussElim(A,b)

% Fişierul gaussElim.m

% Această subrutină va realiza eliminarea gaussiană

% pe matricea în cauză.

% ex. Date fiind A şi b se pot utiliza în găsirea lui x,

% Ax = b

% Pentru a rula fişierul trebuie specificate câteva

% lucruri:

% A – matricea pentru partea stângă.

% b – vector pentru partea dreaptă.

% Rutina va returna vectorul x.

% ex: [x] = gaussElim(A,b)

% aceasta va realiza eliminarea gaussiană pentru a găsi x.


N = max(size(A));
% Realizarea eliminării gaussiene
for j=2:N,

for i=j:N,

m = A(i,j-1)/A(j-1,j-1);

A(i,:) = A(i,:) - A(j-1,:)*m;

b(i) = b(i) - m*b(j-1);

end


end
% Realizarea substituţiei
x = zeros(N,1);

x(N) = b(N)/A(N,N);


for j=N-1:-1:1,

x(j) = (b(j)-A(j,j+1:N)*x(j+1:N))/A(j,j);

end
Pentru a afla vectorul x, pur şi simplu se apelează rutina după nume. De exemplu, se pot face următoarele:

>> A = [1 2 3 6; 4 3 2 3; 9 9 1 -2; 4 2 2 1]


A =
1 2 3 6

4 3 2 3


9 9 1 -2

4 2 2 1
>> b = [1 2 1 4]'


b =
1

2

1



4
>> [x] = gaussElim(A,b)

x =
0.6809

-0.8936

1.8085


-0.5532
>>

Există cazuri când se vrea ca rutina în cauză să apeleze o altă rutină specificată. Subrutina este capabilă să apeleze o funcţie, f(x,y), specificată, folosind Metoda lui Euler.

Urmează o scurtă expunere a fişierului eulerApprox.m:
function [x,y] = eulerApprox(startx,h,endx,starty,func)

% fisier: eulerApprox.m

% Această subrutină în matlab va găsi aproximarea dată de

% y' = func(x,y)

% y(startx) = starty

% Pentru a rula fişierul mai întâi va trebui să se specifice

% următoarele:

% startx : valoarea de început pentru x

% h : pasul

% endx : valoarea de sfârşit pentru x

% starty : valoarea iniţială

% func : numele rutinei: trebuie specificată de tip string.

% ex: [x,y] = eulerApprox(0,1,1/16,1,'f');

% va returna aproximarea funcţiei unde x e de la 0 la 1 în pas de 1/16

% Valoarea iniţială e 1.

% Rutina va genera doi vectori. Primul vector este x care reprezintă o multitudine de puncte, începând de la x0=0 şi având pasul h.

% Al doilea vector este o aproximare a funcţiei specificate.

x = [startx:h:endx];

y = 0*x;

y(1) = starty;

for i=2:max(size(y)),

y(i) = y(i-1) + h*feval(func,x(i-1),y(i-1));

end

În acest exemplu, se va aproxima funcţia, y'=1/y. Pentru a face acest lucru, se va crea fişierul f.m folosind următoarele comenzi:



function [f] = f(x,y)

% Evaluarea părţii drepte a unei ecuaţii diferenţiale

f = 1/y;
Având subrutina definită, acesta se poate apela oricând e necesar.

>> help eulerApprox


file: eulerApprox.m

Această subrutină matlab va găsi aproximarea funcţiei dată de:

y' = func(x,y)

y(startx) = starty

Pentru a rula acest fişier mai întâi vor trebui specificate următoarele:

startx : valoarea de început pentru x

h : pasul

endx : valoarea de sfârşit pentru x

starty : valoarea iniţială

func : numele rutinei pentru a calcula partea dreaptă a funcţiei; trebuie specificată de tip string.

ex: [x,y] = eulerApprox(0,1,1/16,1,'f');

Va returna aproximarea funcţiei, unde x este de la 0 la 1 în pasul de 1/16. Valoarea iniţială este 1 şi pentru calculul părţii drepte a funcţiei se foloseşte o subrutină dată de f.m.

Rutina va genera doi vectori: primul este x, un şir de la x0=0 cu pasul h, iar al doilea vector este o aproximare a funcţiei specificate.

>> [x,y] = eulerApprox(0,1/16,1,1,'f');

>> plot(x,y)

Când subrutina este pregătită, va returna doi vectori şi-i va depune în x si y.

5.Optimizarea apelurilor în subroutine

5.1 Introducere

Această documentaţie prezintă o serie de optimizări cu sau fără restrângeri a subrutinelor. Intenţia este ca subrutina să utilizeze cei mai buni algoritmi atât din punct de vedere al timpului de execuţie cât şi din punct de vedere al spaţiului de memorie folosit. Toate rutinele au apeluri standardizate, iar utilizatorul nu trebuie să ţină cont de parametrii speciali de control a iteraţiilor.



5.2 Optimizări fără restricţii. Minimalizarea unei funcţii scalare

Scop

Găsirea lui x care minimalizează F(x), unde x = [x1,…, xn]T   este vectorul de parametri necunoscuţi, iar funcţia scalară F este o funcţie continuă, derivabilă de două ori. Utilizatorul trebuie să realizeze o subrutină care evaluează F(x) şi gradientul g(x).



Yüklə 359,7 Kb.

Dostları ilə paylaş:
1   2   3   4   5   6




Verilənlər bazası müəlliflik hüququ ilə müdafiə olunur ©muhaz.org 2024
rəhbərliyinə müraciət

gir | qeydiyyatdan keç
    Ana səhifə


yükləyin