Poboljšanje Propusnosti: Primer - Osnovni Problem

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 14

11/30/2015

Poboljanje propusnosti

Primer Osnovni problem


public partial class Form1 : Form
{ void velikiObracun()
int brojac = 0; {
public Form1() System.Threading.Thread.Sleep(2000);
{ }
InitializeComponent();
} private void timer1_Tick(object sender,
EventArgs e)
{
private void button1_Click(object sender,
EventArgs e) brojac++;
{ label1.Text = brojac.ToString();
velikiObracun(); // usporava odziv }
} }

1
11/30/2015

Task reenje problema

Podrazumevani Task upuuje na metodu bez argumenata:


// moe se proslediti metoda bez objekta Action
void velikiObracun()
Task task = new Task(velikiObracun); {
System.Threading.Thread.Sleep(2000);
task.Start(); }

Task koji upuuje na metodu sa argumentom:


Action<object> a;
a = velikiObracun; void velikiObracun(object ms)
{
Task task = new Task(a, 2000); System.Threading.Thread.Sleep((int)ms);
task.Start(); }

Produavanje niti

private void button1_Click(object sender, void velikiObracun()


EventArgs e)
{
{
button1.BackColor = Color.Green;
Task task = new Task(velikiObracun);
System.Threading.Thread.Sleep(2000);
task.Start();
}
Task noviTask =
task.ContinueWith(korektivniObracun); void korektivniObracun(Task task)

} {
button1.BackColor = Color.Red;
System.Threading.Thread.Sleep(2000);
}

2
11/30/2015

Ako se prvi zadatak ne prekida i nema izuzetaka onda se moe produiti i na


sledei nain:
Task task = new Task(velikiObracun);
task.ContinueWith(korektivniObracun);
task.Start();

Sinhronizacija niti

Obustavlja izvravanje niti dok se zadatak task ne zavri:


task.Wait();

Obustavlja izvravanje niti dok se oba zadatka ne zavre:


Task.WaitAll(task, task2);

Obustavlja izvravanje niti dok se bar jedan zadatak ne zavri:


Task.WaitAny(task, task2);

3
11/30/2015

Paralelizam

Task u realizaciji paralelizma

Primer 1a: Poetni problem sa sporim sinhronim odzivom.

private void button1_Click(object sender, EventArgs e)


{
velikiRacun();
}
void velikiRacun()
{
System.Threading.Thread.Sleep(5000);
this.BackColor = Color.Green;
}

4
11/30/2015

Primer 1b. Primer jedne metode koja se asinhrono izvrava, ali i dalje sporo!

private void button1_Click(object sender, EventArgs e)


{
Task t1 = new Task(velikiRacun);
t1.Start();
this.BackColor = Color.Red;
}
void velikiRacun()
{
System.Threading.Thread.Sleep(5000);
this.BackColor = Color.Green;
}

Primer 2a. Podela jedne spore metode na vie manjih metoda

void velikiRacun()
{
for (int i = 1; i < 5; i++)
{
velikiRacunModifikovan(i);
}
this.BackColor = Color.Green;
}
void velikiRacunModifikovan(object i)
{
System.Threading.Thread.Sleep((int)1000);
}

5
11/30/2015

Primer 2b. Poziv manjih metoda paralelno. Ubrzavanje!

private void button1_Click(object sender, EventArgs e){ void velikiRacun(){

velikiRacun(); Task[] t = new Task[5];

} for (int i = 0; i < 5; i++) {

void velikiRacunModifikovan(object i){ t[i] = new Task(velikiRacunModifikovan, i);

System.Threading.Thread.Sleep((int)1000); t[i].Start();

} }
Task.WaitAll(t);
this.BackColor = Color.Green;
}

Klasa Parallel Mala izmena u argumentu metode velikiRacunModifikovan

void velikiRacunModifikovan(int i)
{
System.Threading.Thread.Sleep((int)1000);
}

Omoguava da paralelizuju neke uobiajene programske aktivnosti bez redizajna aplikacije.


Ona kreira sopstveni skup Task objekata i ima nekoliko statikih metoda koje vam stoje na
raspolaganju.

Parallel.For
Definie petlju u kojoj se svaka iteracija moe izvravati paralelno u posebnom zadatku.
Metoda ima poetnu, krajnju vrednost i metodu koja prima celobrojnu vrednost.
Parallel.For(0, 5, velikiRacunModifikovan);

Parallel.ForEach<T>
Slino iskazu foreach, definie petlju u kojoj se sve iteracije mogu paralelno izvravati. Iskaz
prima argument tipa Ienumerable<T> i upuuje se na metodu koja prima argument tipa T
int[] i = { 0,1,2,3,4 };
Parallel.ForEach<int>(i, velikiRacunModifikovan);

6
11/30/2015

Parallel.Invoke
Izvravanje skupa metoda bez parametara kao paralelnih zadataka. Na
primer:
Paralell.Invoke(metod1, metod2, trecametoda);

Obustavljanje zadataka

Neophodno je imati mogunost prekida dugih zadataka.


Prekid bi trebao da se zavri u nekom od moguih ili prihvatljivih stanja.
Klasa Task implementira upotrebu jedne strukture za kontrolisani prekid koja
se naziva CancellationToken.
Ako se namerava obustaviti zadatak, tada se podeava svojstvo
IsCancellationRequested na true. Metoda koja se izvrava moe da proverava
vrednost ovog svojstva u razliitim takama izvravanja i da zahteva prekid.
Metoda moe i da zanemari ovaj zahtev i nastavi sa radom.
Aplikacija kreira CancellationToken kreirajui objekat
CancellationTokenSource, koji sama koristi za kontrolu prekida.

7
11/30/2015

Primer
CancellationTokenSource cancelS = new void velikiRacun(object t)
CancellationTokenSource(); {
CancellationToken cancelT; CancellationToken token = (CancellationToken)t;
System.Threading.Thread.Sleep((int)5000);
private void button1_Click(object sender, EventArgs e) if (token.IsCancellationRequested)
{ {
cancelT = cancelS.Token; this.BackColor = Color.Green;
Action<object> a = velikiRacun; return;
Task t = new Task(a, cancelT); }
t.Start(); System.Threading.Thread.Sleep((int)15000);
} this.BackColor = Color.Green;
}
private void button2_Click(object sender, EventArgs e)
{
cancelS.Cancel();
}

Asinhrone opoeracije

8
11/30/2015

Asinhrone operacije

Pogledajmo kod sa bez i sa primenom klase Task:

private void button1_Click(object sender, EventArgs e)


private void button1_Click(object sender, EventArgs e)
{
{
Task t = new Task(dugotrajnaMetoda1);
dugotrajnaMetoda1();
t.ContinueWith(dugotrajnaMetoda2);
dugotrajnaMetoda2();
t.Start();
label1.Text = "KRAJ";
label1.Text = "KRAJ";
}
}
private void dugotrajnaMetoda1()
private void dugotrajnaMetoda1()
{
{
System.Threading.Thread.Sleep(5000);
System.Threading.Thread.Sleep(5000);
}
}
private void dugotrajnaMetoda2()
private void dugotrajnaMetoda2(Task t)
{
{
System.Threading.Thread.Sleep(5000);
System.Threading.Thread.Sleep(5000);
}
}

Napomena: Za prvi kod poruka se pojavljuje nakon 10sek a drugi odmah. Za prvi sluaj imamo
blokiranje, a u drugom netano prikazivanje poruke o zavretku posla.

Koje su opcije?
1. Saekati da se zavre zadaci pa onda pokazati poruku
private void button1_Click(object sender, EventArgs e)
{
Task t = new Task(dugotrajnaMetoda1);
t.ContinueWith(dugotrajnaMetoda2);
t.Start();
t.Wait();
label1.Text = "KRAJ";
}
Problem blokiranja tekue niti ostaje.

9
11/30/2015

2. Dodati novu metodu u red za izvravanje zadataka koja bi prikazivala


poruku.
private void button1_Click(object sender, EventArgs e)
{
Task t = new Task(dugotrajnaMetoda1);
t.ContinueWith(dugotrajnaMetoda2);
t.ContinueWith(poruka);
t.Start();
t.Wait();
}
private void poruka(Task t)
{
label1.Text = "KRAJ";
}

Meutim pojavljuje se

Objanjenje problema
i novo reenje
Samo nit korisnikog interfejsa moe da upravlja kontrolama interfejsa!
Reenje je u korienju metode Invoke
private void button1_Click(object sender, EventArgs e)
{
Task t = new Task(dugotrajnaMetoda1);
t.ContinueWith(dugotrajnaMetoda2);
t.ContinueWith(poruka);
t.Start();
}

private void poruka(Task t)


{
zaUImetode objMetode = new zaUImetode(porukaUI);
label1.Invoke(objMetode);
}

delegate void zaUImetode();


private void porukaUI()
{
label1.Text = "KRAJ"; Da li ovo moe biti jednostavnije uraeno?
}

10
11/30/2015

Koncept asinhronih operacija

.NET 4.0 uvodi nov pristup, nazvan asinhroni ablon baziran na zadacima. Pre
uvoenja ovog ablona kada su programeri elili da reavaju neki problem
asinhrono, morali su da definiu redosled izvravanja, dok im je ovaj sablon
im je omogucio da rade sa kodom kao da je sinhron.
Instanca Task klase ukazuje na vrednost koja e biti prosleena u odreenom
trenutku u budunosti. Ne treba da brinete kako i u kojoj niti e se izraunavati
ova vrednost. Treba samo da znate da je neophodno izvesno vreme za odreivanje
rezultata, a vi moete da koristite Task objekat za spreavanje blokiranja
trenutnog izvravanja dok ekate rezultate.
Pomou Task objekta moete da proveravate status asinhronog izvravanja,
da ekate da se izvravanje okona, odnosno da dobijete rezultujuu
vrednost. Postoji ak i generika vrednost ove klase Task<TResault> koju
moete da koristite prilikom pristupanja rezultatima razliiih asinhronih
operacija u kojima se primenjuje jaka tipiziacija.

Nove kljune rei

Nove kljune rei async modifikator i await operator. Pomou njih


prebacujete na programskog prevodioca "fiziki posao" pretvaranja sinhronog
koda u asinhroni.
Async koristimo da bi ukazali prevodiocu na to koji blok koda treba da
se izvrava asinhrono, a await koristimo za operaciju koja moe da se
izvrsava due od ostalih da bi se spreilo blokiranje niti koja se izvrava.
Ranije, do pojave ovog modela, ekali smo da se pojavi zavrni dogaaj
pomou rukovaoca dogaajem, nakon cega smo vraali upravljanje na pozivni
metod, operator await upravo to omoguava.

11
11/30/2015

Ukoliko primenite await u funkciji koja se dugo izvrava u nekom asinhronom


metodu, daju se instrukcije programskom prevodiocu da tretira ostatak
izvravanja ovog koda pomou posebnog rukovaoca za taj zadatak, a zatim
da se vrati u pozivni metod. Nakon to se izvri zadatak, inicira se nastavak
izvrsavanja, to omoguava da se nastavi u sinhronom radu.
Asinhroni metodi ne startuju nove niti, umesto toga oni koriste dobro
poznate pozivne metode, ali ste vi posteeni od primene celokupnog
postupka za njihovo kreiranje. Zapravo programski prevodilac obavlja
tei deo posla, tako sto generie kod koji u potpunosti upravlja tokom
izvravanja. Da bi se obili eljeni rezultati oekivana operacija mora da vrati
void, Task ili Task<T> instance.

Reenje 1.
private async void button1_Click(object sender, }
EventArgs e)
{ private void dugotrajnaMetoda1()
await dugotrajnaMetodaA(); {
await dugotrajnaMetodaB(); System.Threading.Thread.Sleep(5000);
}
label1.Text = "KRAJ"; private void dugotrajnaMetoda2()
} {
System.Threading.Thread.Sleep(5000);
private Task dugotrajnaMetodaA() }
{
Task t = new Task(dugotrajnaMetoda1);
t.Start();
return t;
}
private Task dugotrajnaMetodaB()
{
Task t = new Task(dugotrajnaMetoda2);
t.Start();
return t;

12
11/30/2015

Reenje 2.
private async void button1_Click(object sender, EventArgs e)
{
Task t1 = Task.Run(new Action(dugotrajnaMetoda1));
private async void button1_Click(object Task t2 = Task.Run(new Action(dugotrajnaMetoda2));
sender, EventArgs e)
{ await t1;
await t2;
Task t1 = new Task(dugotrajnaMetoda1);
t1.Start(); label1.Text = "KRAJ";
}
Task t2 = new Task(dugotrajnaMetoda2);
t2.Start();
await t1;
await t2;
private async void button1_Click(object sender, EventArgs e)
label1.Text = "KRAJ"; {
Task t1 = Task.Run(()=> { System.Threading.Thread.Sleep(5000); });
} Task t2 = Task.Run(() => { System.Threading.Thread.Sleep(5000); });
await t1;
await t2;

label1.Text = "KRAJ";
}

Asinhrone metode koje vraaju vrednost

Primeri do sada su imali asinhrone metode koje ne vraaju vrednost, tj.


Koriste objekat tipa Task za izvravanje asinhronih operacija. U ovom sluaju
radi se sa tipom: Task<T>
Neka naa metoda vraa neki rezultat:

private void button1_Click(object sender, EventArgs e) private void button1_Click(object sender, EventArgs e)
{ {
Task<bool> task = new Task<bool>(velikiObracun); Task<bool> task = Task.Run(()=>velikiObracun());
task.Start(); task.Start();

MessageBox.Show("Dobijeni rezultat: " + task.Result); MessageBox.Show("Dobijeni rezultat: " + task.Result);


} }

bool velikiObracun()
{
System.Threading.Thread.Sleep(5000);
return true;
}

13
11/30/2015

A realizacija asinhrone metode je slina ranije definisanim:

private async void button1_Click(object sender, EventArgs e)


{
Task<bool> task = new Task<bool>(velikiObracun);
task.Start();
await task;
MessageBox.Show("Dobijeni rezultat: " + task.Result);
}

14

You might also like