Using TaskCompletionSource in wraping event handler


Using TaskCompletionSource you can wrap any operation in to task, so that you can do anything you can with the task object. The TaskCompletionSource class is very important and today’s post will be explain how to wrap button click event in to TaskCompletionSource. With this wrap we will see how complicated operation behind click button handler can be simplified.

The for this blog post is simple Windows Store app shown on the picture below.

screen_sample2

When the Play Slides is clicked, Image slide is started which start animation of images. XAML code behind this app is listed here:

<Page.Resources>
    <Storyboard x:Name="animImageSlideIn">
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)"
                                        Storyboard.TargetName="img">
            <EasingDoubleKeyFrame KeyTime="0" Value="900"/>
            <EasingDoubleKeyFrame KeyTime="0:0:2" Value="0" />
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Width="200" Height="250" >
        <Button x:Name="playbtn" Height="50" Margin="0,5,0,5" Content="Play Slides" HorizontalAlignment="Center" Click="playbtn_Click"></Button>

        <Image x:Name="img" HorizontalAlignment="Center">
            <Image.RenderTransform>
                <CompositeTransform TranslateY="900" />
            </Image.RenderTransform>
        </Image>
    </StackPanel>
</Grid>

First, it will be presented  the implementation without TaskCompletionSource. The Play Slides Click event is the following code:

private async void  playbtn_Click(object sender, RoutedEventArgs e)
{
    int i = 1;

    EventHandler<object> handler = null;

    handler = delegate
    {
        if (i <= 3)
        {
            playbtn.Content = string.Format("Slide Image {0}",i);

            LoadSourceImage(i);

            animImageSlideIn.Begin();

            i++;
        }
        else
        {
            playbtn.Content = "Play Slides";
            animImageSlideIn.Completed -= handler;
            LoadSourceImage(0);

        }
    };

    animImageSlideIn.Completed += handler;
    handler(null,null);
}

As we can see from the listing above the code is pretty much long and little bit confused because we subscribe to the handler and call it as much as we reach the magic number of slides. Whe the number of slides is reached we unsubscribed from the handler and exit  the method.

Now implement the same functionality with the TaskCompletionSource class. The following listing shows the implementation:

private async void playbtn_Click(object sender, RoutedEventArgs e)
{

for(int i=1; i<=3; i++)
{
playbtn.Content = string.Format("Slide Image {0}",i);
LoadSourceImage(i);
await animImageSlideIn.RunAsync();
}

playbtn.Content = "Play Slides";
}

As we can see the implementation is very simple and concise. in for loop we call LoadSourceImage then asynchrony run animation.

The source code of the demo can be found by clicking the image below:

This blog post is inspired by Stephen Toub //build/ session.

Advertisements

Pausing and cancelling async method in C#


Responsiveness of your app is not just fee UI thread by implementing async. It is more that that. When a long operation is under process in your app, user sometimes wants to cancel it  or  pause the operation. Imagine your app processing hundreds of files or images. Such a operation can take more that few seconds and user must have option to cancel it. Canceling and pausing are very important feature for every app that implements long operations.

This blog post will present the way of using CancelationToken built in cancel feature in .NET, as well as a PauseToken custom implementation which is very similar to CancelationToken.

Original implementation of PauseToken is from the pfxteam blog which you can find here.

We will implement simple Windows Store app with cancel and pausing the async operation. The picture below shows the sample app:

screen_sample1

 

As you can see when the Start Process button is clicked it begins process of processing image files. There is also ProgressRing control which shows the progress and percentage of completeness. From the right side you can see two buttons. The Cancel button cancels the operation, and pause button pauses operation until the Pause button is clicked again.

The implementation behind Process button is the folowing:

private async  void btnProcess_Click(object sender, RoutedEventArgs e)
{
    //creating cancel and pause token sources
    m_pauseTokeSource = new PauseTokenSource();
    m_cancelationTokenSource = new CancellationTokenSource();

    //get al picture from picture library
    var picturesFolder = KnownFolders.PicturesLibrary;
    var fileList = await picturesFolder.GetFilesAsync();

    //set ProgressRing to active
    ring2.IsActive = true;

    try
    {
        //asynchrony process files, by passing pasue and calcel tokens

        await ProcessImages(fileList, m_pauseTokeSource.Token, m_cancelationTokenSource.Token);
    }
    catch (Exception)
    {
        //do nothing when somthing went wrong not when taks is canceled
    }
    finally
    {
        //make inactive ProgressRing
        ring2.IsActive = false;
    }
}

Click event implementation of the Start Process button 

First we create Cancel and Pause Source tokens. Gent the picture content in form of list of files. Then we call asynchonious ProcessImages method by passing list of images files, cancel and pause tokens. Process images is called within try catch finally blocks, because every cancel task throws exception.

Implementation ProcessImages async method

ProcesImage method is async method which accept cancelation and pasue token nad returns Task object.

public async Task ProcessImages(IEnumerable<StorageFile> images, PauseToken pauseToken, CancellationToken cancelToken)
{
    double count=images.Count();
    double current=0;
    foreach (var file in images)
    {
        //if the paise is active the code will wait here but not block UI thread
        await pauseToken.WaitWhilePausedAsync();

        ring2Text.Text = string.Format("{0}%",(int)(100*current / count));

        await ProcessAsync(file, cancelToken);
        current++;
    }
    ring2Text.Text = string.Format("100%");
}

In foreach loop first we await pauseToken.WaitWhilePausedAsync(); which wait if IsPause property of the Token class is true, otherwize there is no awaiting here. The next await is out Delay which takes cancelation token as parameters. When the Pause button is clicked, pauseToken is awaiting until the pause button is clicked again. In case of cancelation when the Cancel button is clicked the Cancel() method of the cancelationTokenSource is called and exception is thorwn. Then processImages method is interupted and finally blick progressring is disabled.
Pause and Cancel Click implementation are shown in the following listing:

private void btnPause_Click(object sender, RoutedEventArgs e)
{
 m_pauseTokeSource.IsPaused = !m_pauseTokeSource.IsPaused;
}

private void btnCancel_Click(object sender, RoutedEventArgs e)
{
 m_cancelationTokenSource.Cancel();
}

Complete source code can be downloaded from link below.

MSNetwork 3: Paralelno i asinhrono programirnje primjeri i prezentacijska datoteka


msnetwork

U ovom postu pobrojani su svi demo primjeri  sa kratkim objašnjenjem koje sam na MSNetwrok 3 predavanju demonstrirao. Ovo ujedno i predstavlja moje aktivnosti zadnjih nekoliko godina vezanih oko ove teme.

Tačno prije 5 godina odnosno u aprilu 2008 godine (22. aprila 2008.) napisao sam prvi članak oko paralelnog programiranja, dok je 5 mjeseci ranije te godine izbačena prva CTP verzija ParallelFx biblioteke.

Ovim MSNetwork predavanjem želio sam ujedno i da sve to objedinim i da široj javnosti prenesem iskustva iz ovog područja programiranja. Ovaj blog post sadrži izvorni kod za sve demo primjere koji su planirani za ovo predavanje. Moguće je, (jer blog post pišem ranije) da neki od primjera nije demonstriran zbog vremena, pa ovom prilikom ih objavljujem sviju sa kratkim pojašnjenjem.

Ukupno za ovo predavanje planirano je 9 demo primjera i to:

1. Power point prezentacija predavanja.

2. Demo primjeri sa predavanja

Primjer manipulacije sa objektom Thread, i kako manipulisati u višenitnom okruženju.
Primjer manipulacije sa Task objektom, kao osnovnim konceptom pralelnog i asinhronog programiranja.
Demo sadrzi 5 različitih primjera korištenja for, foeach, parallelLoopState i primjer koordinacije i razmjene podataka izmedju niti.
PLINQ primjer koristenja paraleliziranih LINQ upita.
Primjer korištenja Partisionera, kojim dijelimo poslove na više taskova.
Primjer koji demonstrira Race Condition fenomen kada dvije niti u isto vrijeme pokusavaju da promjene vrijednost varijable.
Realni primjer primjene ParallelFx u rjesavanju sistema linearnih jednačina sa 1000 nepoznatih.
Primjer asinhronog programiranja na strani klijenta. Kako stari sekvencijalni kod pretvoriti u asinhroni.
Primjer asinhronog programiranja na strani servera. Korištenje asinhronog programiranja u optimizaciji ASP.NET aplikacija i mogućnosti povećavanja performansi i odziva aplikacija.

MSNetwork 3. po redu Microsoft konferencija u BiH


msnetwork

Banja Vrućica 3. i 4. aprila 2013 g.

Sada već tradicionalno po treći put se održava Bosanskohercegovačka Microsoft konferencija:  MSNetwork 3. Mjesto održavanja ovaj put je Banja Vrućica zdravstveno turistički centar koji se nalazi u blizini Teslica, gradića na putu izmedju Banjaluke i Doboja.

Kao i prvi put kad se održavala u Banjaluci prije 3 godine, i ovaj put konferencija će ponuditi najbolje teme, predavače i cijelu konferenciju učiniti nezaboravnom bas onako kako je to bilo i ranije. Naravno, svaki put ljudi iz Microsofta BiH se potrude da ona bude bolja od prethodne pa i ovaj put ne sumnjam u to. Ovaj put rekordan broj predavača kao i predavanja. Prva konferencija je krenula sa 3 tracka, da bi prošle godine bio i MSC track na kojem predavanja daju ljudi iz MS Communitya, da bi ove godine bio i EDU track, posvećen nekim stručnim  temama.

Na ovoj konferenciji se se naći zaista za svakog ponešto. Gotovo svi poznati  predavači iz Makedonije, Srbije, BiH, Hrvatske i Slovenije, posebno predavači iz Njemačke i drugih evropskih zemalja,  naći će se 3 i 4 aprila u Banja Vrućici. Ukupno 60 predavača govorit će na konferencij što konferenciji čini vrlo atraktivnom, kvalitetnom i zanimljivom.

Koristim ovu priliku da na MSNetwork najavim svoje predavanje. Predavati na MSNetwork konferenciji zaista me čini sretnim i zahvaljujem se organizatorima što su ovo predavanje  uključili u zvanični dio konferencije.

Naziv predavanja, level i kratki opis pročitajte u narednom tekstu.

Paralelno i asinhrono programiranje – izazov za svakog programera (4.april. 2013, 11:30 dvorana Bosna)

par_asyn_conc

Level: 300

Opis predavanja:

Multi-core procesori su realnost, proizvođači ih danas ugrađuju i u grafičke kartice, mobilne telefone pa čak i u veš-mašine. Direktna posljedica razvoja multi-core procesora je prestanak razvoja single-core procesora čiji takt već odavno stoji na magičnoj brojci oko 3 GHz. Kako proizvođači ovom tehnologijom ne mogu povećati takt počeli sa proizvodnjom multi-core procesora, ili višejezgrenih procesora u jednom hardverskom dijelu, što je dalo dodatni vjetar u leđa razvoju procesora. Danas se kućni računari kupuju sa 4 ili 8 jezgri, serveri i do 128 jezgri. Realno se pitanje postavlja: da li softver koji je razvijan nekoliko godina unazad odgovara takvom hardveru? Da li hardver na multi-core procesorima ima smisla vrtiti dosadašnja softverska rješenja? Moguće se upitati i to da li energija koju troši ovakav hardver odgovara korištenju softvera? Imate više od 1 procesora na PC-u, ali ne primjećujete da vaš softver radi brže? Još uvijek koristite klasu Thread ili BackgroundWorker ili Callback funkciju kako bi korisnika zavaravali dok se vaši podaci učitavaju u pozadini? Željeli bi programirati višenitne aplikacije, a da ne formirate niti? Ovo su samo neka od pitanja, čije odgovore daje paralelno i asinhrono programiranje u .NETu. Paralelno i asinhrono programiranje predstavlja novu paradigmu i izazove za moderne programere koji žele iskorištavati sve resurse PC-a, a ne samo jednu jezgru, koji žele programirati višenitno, a da ne formiraju niti, koji žele koristiti nova proširenja koja su sastavni dijelovi .NET 4.5 i C# 5.0.

Pored zvaničnog opisa ovdje bih dodao da će ovo predavanje obilovati realnim primjerima:

1. primjer paralelizacije riješavanje sistema linearnih jednačina sa više od 1000 nepoznatih.

2. primjer asinhronog procesuiranja zahtjeva na ASP.NET  web stranici.

3. procedura konverzije sekvencijalnog koda u asinhroni, praktična iskustva.

4. nekoliko jednostavnih primjera demonstracije Data Race, Thread-Safety, PLINQ,ThreadLocalState i sl.

Nadam se da će predavanje biti zanimljivo, a pogotovu za one koji žele više posmatrati Visual Studio od PowerPointa.

Vidimo se na konferenciji.

How to convert your old sequential code in to async


There are plenty of ansyc samples over the internet, and most of them are different and not satisfy your requirements. Actually, async pattern depends of its creator, and can be implement on various ways. It is important to understand the async pattern in order to use it. Only on this way, you can stop searching for exact sample you need, and start coding your own async code.  More that year ago, I wrote simple blog post about async pattern (part 1 and part 2) (Bosnian language), and also wrote how to call Entity Framework with async pattern as well.

Today I am going to show you how old synchronous code block convert in to asynchronous. I think it is interesting because async pattern can improve your existing applications on various ways. First of all async pattern can increase responsiveness of  an application, performance, etc.

First of all, create simple Windows Forms sample and implement synchronous code.This will represent our old application, in which we are going to implement new programming paradigm.

1. Create Windows Forms Project, Name it “WinFormsAsyncSample

2. Design your main form (Form1.cs) exactly as picture shows below, and implement events.

As picture shows we have few labels, one text box, one progress bars, and two buttons.

Note: At the end of the blog you can download both versions (nonasync and async) of this sample.

The sample application calculates how many prime numbers exist in range. You need to enter number, press run button. The program starts counting. The progress bars informs user status of counting.

Lets see the implementation of runBtn_Click event:

private void btnRun_Click(object sender, EventArgs e)
{
    if(!int.TryParse(textBox1.Text,out m_number))
        m_number= 1000000;

    textBox1.Text = m_number.ToString();
    progressBar1.Maximum = m_number;
    progressBar1.Minimum = 0;
    progressBar1.Value = 0;

    //call start calculation
    startCounting();
}

At the beginning of the btnRun_Click we prepare progressBar, and also convert text from textbox in to int type.At the end of the function startConting method is called. Here is the source code of the method:

private void startCounting()
{
    int counter=0;
    for(int i=2;i<m_number; i++)
    {
        bool retVal= IsPrime(i);
        progressBar1.Value++;
        if (retVal)
        {
            counter++;
            label3.Text = "Result is: " + counter.ToString();
        }
    }
}

The method is very simple. It iterates from 2 to specified number by calling helper method IsPrime (see source code of the blog post) to check if certain number is prime. Then the method increased the counter variable and tried to update label about current count value.  If  you run the sample and press run button, you can see that the application is not responsive on user input, and represent classic sequential, synchronous single thread application.

Now I am going to show how this implementation can be converted in to async with minimum code changes.We are going to change only startCounting method, other code will remain the same. Explanation is divided in only 3 steps, which is enough to convert our code in to full async pattern.

  • Put async keyword right after public modifier of startCounting method.

Explanation: Every method which implements async patter needs to be decorated with async.

  • Put sequential implementation in to Task action, and wait.

Explanation: With this, you define a Task object which will run the code without blocking main thread. The simplest implementation is the following:

private async void startCalculation()
{
    var task = new Task(() =>
        {
            int counter = 0;
            for (int i = 2; i < m_number; i++)             {                 bool retVal = IsPrime(i);                 this.Invoke((Action)(()=>
                {
                    progressBar1.Value++;
                    if (retVal)
                    {
                        counter++;
                        label3.Text = "Result is: " + counter.ToString();
                    }

                }));
            }
        });

    task.Start();
    await task;
}

Now if you run the sample, you have fully asynchronous implementation. Main thread is free and can receive user input. So this is the simplest way how to convert your sync code in to async. This is the case when Task object create another thread in order to execute the code. That’s why we called this.Invoke method in order to set controls properties progressBar.Value and label3.Text. Everything else remain the same as in previous implementation.

  • Create global variable of type CancellationTokenSource and call Cancel method from Cancel Event handler.

Explanation: On this way we can cancel counting at any time.With this case we need to implements extra code in our previous implementation like the following.

private async void RunProces()
{
    if (m_IsRunning)
        return;
    m_IsRunning = true;
    int counter=0;
    if (m_ct != null)
    {
        m_ct.Dispose();
        m_ct = null;
    }
    m_ct = new CancellationTokenSource();

    var task = new Task(() =>
        {
            for (int i = 0; i < m_number; i++)             {                 bool retVal = IsPrime(i);                 this.Invoke((Action)(()=>
                {
                    progressBar1.Value++;
                    if (retVal)
                    {
                        counter++;
                        label3.Text = "Result is: " + counter.ToString();
                    }

                }));

                if (m_ct.IsCancellationRequested)
                {
                    m_IsRunning = false;
                    return;
                }
            }
        }, m_ct.Token);

    task.Start();
    await task;
}

With the last code implementation you have full of async patter in yur old application.

In this blog post I have tried to explain as simple as possible the way how you can convert you old sync code in to new async programming pattern.

Source code sample used in this blog post:

On this link you can find sequential version of the sample.

On this link you can find the final solution of async pattern.


					

async i await – višenitno programiranje bez niti II dio


Novine koje dolaze sa C# 5.0 već su postale „lanjski snijeg“, obzirom da je već prošlo 4 mjeseca od pdc10 na kojem je Anders Hejlsberg prezentirao buduću verziju C# 5.0. Pored kompajler kao servis, i još nekoliko novina, prezentiran je novi koncept programiranja nazvan asinhrono programiranje. Šta je asinhrono programiranje i zašto nam može poslužiti, biće prezentirano u nekoliko blog postova.

Teorija iza async i await

Kako smo u prethodnom dijelu napravili uvod u asinhrono programiranje, sada je potrebno definisati nove ključne riječi aync i await koje nam služe da implementiramo asinhronu logiku na način da se direktno ne formiraju niti.

Razlog pojave asinhronog programiranja leži u sve većim zahtjevima koji se postavljaju pred arhitekte i developere, a sastoje se u interakciji sa vanjskim izvorima informacija poput interneta, VPN mrežama i drugim vrstama gdje se reagovanje na zahtjeve može znatno produžiti. S druge strane zahtjevi koji se postavljaju pred dizajnere korisničkog iskustva UX zahtjevaju potpuni ugođaj, odziv u svakom trenutku na korisnikove aktivnostii, te optimizarano vrijeme interakcije korisnik-aplikacija. Pored ovih postoje i drugi zahtjevi poput optimalne iskorištenosti procesorskog vremena u procesiuranju informacija i sl, što je odgovor na razvoj multy-core i many-core procesora. S druge strane, svi ovi zahtjevi posljedica su konstantnog unapredjenja i razvoja hardvera: sve veći razvoj pametnih telefona, tableta, notebooka, interneta društvenih mreža, protoka informacija i korištenja istih.

Microsoft ove zahtjeve i izazove želi riješiti suštinski i ugraditi ih u sami programski jezik što predstavlja pravi dizajnerski podvig. Samim tim što želi imati ovako složenu logiku iza samo dvije ključne riječi async i await .NET programske jezike C# i VB postavlja daleko ispred svojih konkurenata. Asinhrona tehnika programiranja te počinje da se razvija i još puno toga ćemo čuti na račun async i await.

No krenimo ispočetka i pokušajmo vidjeti kako radi koncept asihronog mehanizma preko async i await.

“LongRunnging” operacije ili dijelove koda, koje želimo da nam ne blokiraju UI nit, dekorišemo sa ključnom riječju await. Kako metoda koja je dekorisana sa await treba da vrati objekat tipa Task<T> moguće je nekoliko scenarija, koja će biti definisana kasnije. Metoda koja neposredno poziva “LongRunning” operaciju dekoriše se sa ključnom riječju async, koja upućuje kompajleru da se u tijelu ove metode koriste asinhrone operacije. Sljedeći listing pokazuje primjer korištenja ključnih riječi:

//Svaka metoda sa async označena je kao asinhrona
private async void AsyncOperationSample()
{
    for (int i = 0; i < 100; i++)
    {
        //await- omogućava da se izvrši operacije bez blokiranja UI niti
        await TaskEx.Delay(100);
    }
}

Na koji način gornji primjer radi?
Da bi u potpunosti shvatili gornji listing potrebno se prisjetiti šta je Task u konceptu TPL-a (Task Parallel Library)- novog proširenja u .NET 4.0. Kako je Task asihnhrona operacija koja će u budućnosti da se izvrši i da vrati vrijednost tipa T, tako i cijela linija predstavlja asinhronu operaciju koja može biti tretirana od strane JIT kompajlera na više načina:

  1. Način je da se operacija izvrši trenutno, odnosno da await operator izvrši operaciju bez dodatnog formiranja radne niti.
  2. Način je da je Task neka I/O operacija, koja i u ovom slučaju ne formira dodatnu nit već se izvršava otvarajući IO portove i opet bez dodatnih radnih niti.
  3. Način je da se operacija izvrši formirajući jednu ili više niti zavisno od raspoloživog hardvera, a zašto će se postarati klasa Task, te operaciju završiti na optimalan način uz maksimalno iskorištavanje hardvera.

Iz ovog pregleda vidimo da je asinhrono puno više od samog višenitnog programiranja. Ovaj koncept predstavlja jednistven programski model koji ne zavisi od prirode problema koji se programira. Asinhrono programiranje podrazumijeva korištenje jednog koncepta, koji je vrlo sličan sekvencijalnom programskom modelu, u implementaciji raznih scenarija asinhronog programiranja poput: IO, LAN, WAN i In-Memory i sl.

Primjer korištenja async i await

Windows Forms primjer koji smo implementirali u prethodnom blog postu biće tretiran i ovdje. Međutim, da bi koristili ove osobine C# 5.0, potrebno je skinuti Visual Studio ASYNC CTP koji se nalazi na ovom linku.
sl_asyncbr2
U koliko imate već instaliran SP 1 za Visual Studi 2010 na žalost niste u mogućnosti (bar je to kod mene bio slučaj) da koristite ovaj feature jer nije kompatibilan.

Nakon instalacije koja traje nekoliko minuta, u startnom meniju dobijete novu stavku koja vas upućuje na dokumentaciju i puno demo primjera za async, dovoljno da počnete koristiti ovu tehniku.
Formirajte novi Windows Forms projekat te implementirajte kontrole kao na sljedećoj slici. U biti isto što i u primjeru prethodnog posta, samo bez BackgroundWorker komponente.
sl_asyncbr3
Da bi u novom projektu mogli koristiti async i await potrebno je referencirati AsyncCTPLibrary.dll,  CTP biblioteku koja se nalazi u Samples instaliranom u vašem Document folderu. Na sljedećoj slici se vidi način kako se referencira potrebni dll.
sl_asyncbr1
Demo primjer ćemo implementirati u dvije varijante prvu običnu sekvencijalnu, te drugu asinhronu varijantu.

1. Sekvencijalna varijanta:

Deklarišimo događaje za Run Operation 1 i Cancel Operation dugmad i implementirajmo demo tako da ne znamo ništa oko višenitnog i asinhronog programiranja.


private void operation1_Click(object sender, EventArgs e)
{
    SequentialOperation();
}

bool bCancelOperation = false;

private void SequentialOperation()
{
    operation1Btn.Enabled = false;
    cancelOperation1Btn.Enabled = true;
    for (int i = 0; i <= 100; i++)
    {
        if (bCancelOperation)
        {
            bCancelOperation = false;
            MessageBox.Show("Operation is canceled!");
            break;
        }
        progressBar1.Value = i;
        //
        Thread.Sleep(200);
    }
    operation1Btn.Enabled = true;
    cancelOperation1Btn.Enabled = false;
}

private void cancelOperation1_Click(object sender, EventArgs e)
{
    bCancelOperation = true;
}

Iz listinga vidimo da imamo događaj za pokretanje operacije te samu operaciju koja je simulirana sa metodom Sleep. Kada pokrenemo ovakav demo vidimo da je naš UI potpuno zamrznut, te je irelevantno implementirati Cancel Operation1 dugme jer operaciju ne možemo otkazati niti zatvoriti prozor.

2. Asinhrona varijanta

Na potpuno isti način uz korištenje async i await implemenitiraćemo asinhronu verziju ovog primjera.

private void operation1_Click(object sender, EventArgs e)
{
    AsyncOperationSample();
}
bool bCancelOperation = false;
//This method is sample of async operation
private async void AsyncOperationSample()
{
    operation1Btn.Enabled = false;
    cancelOperation1Btn.Enabled = true;

    for (int i = 0; i <= 100; i++)
    {
        if (bCancelOperation)
        {
            bCancelOperation = false;
            MessageBox.Show("Operation is canceled!");
            break;
        }
        progressBar1.Value = i;
        //await yields control until awaited task completes
        await TaskEx.Delay(100);
    }
    operation1Btn.Enabled = true;
    cancelOperation1Btn.Enabled = false;
}
private void cancelOperation1_Click(object sender, EventArgs e)
{
    bCancelOperation = true;
}

U koliko se shvati šta u biti znači ova tehnika, otvaraju se novi i jednostavniji načini implementacija asinhronih operacija, a dosadašnji kompleksni scenariji postaju više funkcionalni i jednostavniji za održavanje. Source code za ovaj primjer možete sinuti sa ovog linka.

async i await – višenitno programiranje bez niti – 1. dio


Novine koje dolaze sa C# 5.0 već su postale „lanjski snijeg“, obzirom da je već prošlo 4 mjeseca od pdc10 na kojem je Anders Hejlsberg prezentirao buduću verziju C# 5.0. Pored kompajler kao servis, i još nekoliko novina, prezentiran je novi koncept programiranja nazvan asinhrono programiranje. Šta je asinhrono programiranje i zašto nam može poslužiti, biće u prezentirano nekoliko blog postova.

Uvod

Kako možemo definisati asinhrono programiranje?

To nije ništa drugo do jedna vrsta višenitnog programiranja, ali bez direktnog formiranja niti.

Kako bi na najjednostavniji način pokušali objasniti asinhrono programiranje potrebno je prvo definisati i detektovati probleme u razvoju aplikacija do kojih je dovela pojava ove vrste programiranja.

Višenitno programiranje zadnjih godina postaje sve više prisutno, jer aplikacije koje se danas razvijaju postaju više ovisne od raznih servisa koji se obično nalaze na udaljenim računarima ili pak u oblacima. S druge strane, postoje aplikacije koje u svom sastavu imaju funkcije koje izvršavaju vrlo duge operacije, pri čemu je korisnički interfejs uglavnom nepomičan i zamrznut, te danas predstavlja staromodan i prevaziđen način dizajniranja aplikacija.

Podsjećanja radi, svaka .NET (slobodno možemo reći i bilo koja Windows) aplikacija posjeduje samo jednu nit i ona se zove UI ili glavna nit (main thread). Bez dodatnog programiranja u dotičnoj aplikaciji sve operacije se izvršavaju sekvencijalno: jedna po jedna odnosno, svaka operacija mora čekati sve prethodne operacije da se izvrše da bi se sama izvršila. Što u kontektu prethodnih razmatranja predstavlja vrlo ozbiljan problem, jer mi želimo da imamo mogućnost izvršavanja, paralelno više operacija odjednom, jer imamo hardver koji to podržava, imamo memoriju koja to može prihvatiti, i na kraju imamo više procesorskih jezgri koje to mogu obraditi. S druge strane zahtjevi kupaca za takvim aplikacijama postalo je must. Pa zašto bi čekali, jer na kraju vrijeme je novac.

Kako .NET danas može doskočiti ovim problemima?

Prvenstveno tako što će „long-running“ operacije „prebaciti“ iz UI niti u radnu nit (worker thread), tako da ova prva bude slobodna i da može reagovati na korisničke aktivnosti.

A kako se ovakve logike implementiraju?

Višenitnim programiranjem koje je u principu složeno i za najiskusnije developere, a posebno onda kad ih je puno i potrebno pronaći neki logički bug, koji se tu pojavio nakon svih mogućih testova. Tad dotični programer kune majku što ga je rodila.

Od samog pojavljivanja .NET višenitno programiranje zastupljeno je u određenoj mjeri i od prve verzije pokušava se ovaj način programiranja usavršiti, što u principu predstavlja i zadaću .NET frameworka. Prije samog upoznavanja sa novim ključnim riječima async i await, vrlo je važno upoznati se sa današnjim tehnikama višenitnog programiranja koje će ovdje kratno biti prezentirane.

Današnje tehnike za višenitno programiranje

Klasa Thread

Formirati radnu nit i u njoj pozvati funkciju da nešto izvrši, jednostano možemo uraditi koristeći klasu Thread, koja se nalazi u System.Threading. Primjer kako se to radi prikazano je na sljedćem listingu.

class Program
{
static void Main(string[] args)
{
// thwo worker thread is constructed
Thread thread1 = new Thread(new ThreadStart(Operation1));
Thread thread2 = new Thread(new ThreadStart(Operation2));
// first start thread 1
thread1.Start();
// then start thread two
thread2.Start();

//Press any key to continue
Console.ReadKey();

}

public static void Operation1()
{
System.Threading.Thread.Sleep(2000);
Console.WriteLine("I am operation one.");
}

public static void Operation2()
{

System.Threading.Thread.Sleep(1000);
Console.WriteLine("I am operation two.");
}
}

Rezultat gornjeg listinga je prikazan na sljedećoj slici.

clip_image002

Sa slike možemo vidjeti da se prva izvršila metoda koja se druga startala tj. Operation2. Po konceptu sekvencijalnog programiranja ovo je nemoguće, ali u koliko smo formirali dvije potpuno neovisne niti, koje se izvršavaju neovisno od glavne UI niti, ovo je potpuno normalno. Oko višenitnog programiranja možete više saznati na linku koji se nalazi u referencama za ovaj blog post.

BackgroundWorker novina u .NET 2.0

Sirovo korištenje Thread klase predstavljalo je problem, jer na mnogim dijelovima u aplikaciji potrebno je formirati samo jednu radni nit, u koju se treba poslati neka operacija za izvršavanje. Novina koja je došla sa .NET 2.0 zvala se BackgrounWorker i predstavljala je jednu od najpopularnijih komponenata u WinForms toolboxu. Formiranje jedne radne niti preko BackgroundWorker komponente postalo je dosta pojednostavljeno. Na sljedećoj slici prikazan je jedan od načina kako definisati ovu komponentu u aplikaciji. Obzirom da se nalazila kao komponenta u Toolboxu, drag & drop funkcijom moguće je formirati u aplikaciji.

clip_image004

Nakon povlačenja i spuštanja u formu (br. 1), potrebno je definisati događaje: DoWork 1, ProgressChanged 2 i ProgressCompleted 3, te implementirati logiku. Naredni listing prikazuje kako radi BackgroundWorker.

Pored definisanja događaja potrebno je backgroundWorker podesiti da obavještava o progresu, na način kako je prikazano na slici.

Kada kliknemo na dugme Operation1, program starta sa procesuiranjem, i nakon svakog intervala preko ProgressChanged informacija o progresu se proslijedi, te na kraju procesuiranja pozove ProgressCompleated informirajući da se operacija zavrsila. Važno je napomenuti da su ovi događaji pozivaju u UI niti, i slobodno možemo „dirati“ kontrole Form1.

public partial class Form1 : Form
{

public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
//Call DoWork in workre thread
backgroundWorker1.RunWorkerAsync();
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 100; i++)
{
Thread.Sleep(500);
//Reports progress about operation state
backgroundWorker1.ReportProgress(i+1);
}
}

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Operation1 has been completed.");
}
}

BackgroundWorker je pravo jednostavan, ali pri složenijoj logici ipak moramo pribjeći formiranju objekata Thread klase, te se upustiti u pustolovinu višenitnog programiranja.

Zaključak

Prethodno su prikazane najčešće tehnike za višenitno programiranje te stoga i dovoljna uvertira u analizu novih ključnih riječi u C# 5.0 i višenitnog odnosno asinhronog programiranja.

U sljedećem postu upustićemo se u analizu async i await ključnih riječi te vidjeti kako programirati višenitno bez niti, ili u prevodu kako sekvencijalan kod natjerati da radi višenitno, te pokušati prognozirati da li je stvarno došao kraj višenitnom programiranju kao jednom od najsloženijih tehnika programiranja.

Izvorni kod za prvi dio članka o asinhronom programiranju možete skinuti sa ovog linka. Ažurirana verzija izvornog koda može se pronaći na ovom linku.

References:

1. http://www.c-sharpcorner.com/uploadfile/mgold/multithreadingintro10062005000439am/multithreadingintro.aspx