Parallelle code

Hoewel asynchrone code de UI-thread niet blokkeert en zo dus de illusie geeft van verbeterde performance is dit slechts een illusie. Beide operaties doen er exact even lang over om hun methodes te voltooien: 17 seconden. Het enige verschil is dat de gebruiker tijdens de berekeningen de app kan blijven gebruiken of er kan bijvoorbeeld een ‘loading’ animatie getoond worden.

Hoewel asynchrone code de app responsief houdt, hebben we qua loading time geen vooruitgang geboekt

Het zou handig zijn als long running operations  — die niet van elkaar afhankelijk zijn – naast elkaar zouden uitgevoerd kunnen zodat we de totale runtime kunnen terugdringen naar de duur van de langst lopende operatie, i.p.v. de som van de duur van alle operaties. Om dit te bereiken kunnen we een concept gebruiken dat bekend staat als parallelle code.


In parallel programmeren is de totale laadtijd gelijk aan de duur van de langste operatie en niet aan de som van alle operaties.

Om verschillende asynchrone methodes gelijktijdig te laten uitvoeren, moeten we deze toevoegen aan een Enumerable zoals een List. Alle operaties moeten dus hetzelfde return types hebben, aangezien we in C# enkel collecties kan maken van objecten van hetzelfde datatype. In dit geval gebruiken we dezelfde methodes die uitgevoerd worden in de ExecuteAsync methode. Deze methodes hebben allen het datatype Task. Daarna kunnen we await Task.WhenAll() uitvoeren op deze collectie. Visual Studio zal nu alle methodes in deze collectie gelijktijdig uitvoeren en wachten tot ze allemaal voltooid zijn.

private async void BtnParallelClicked(object sender, RoutedEventArgs e)
{
            ResultsWindow.Text = "Startup parallel operation";

            // In parallel programming, all operations that are to be executed simultaneously are added to a List of type Task<T>.
            var parallelTasks = new List<Task>
            {
                ShortRunningOperationAsync(),
                MediumRunningOperationAsync(),
                LongRunningOperationAsync()
            };

            // Run all tasks in list concurrently and wait for all to complete
            Stopwatch timer = Stopwatch.StartNew();
            await Task.WhenAll(parallelTasks);
            timer.Stop();

            ResultsWindow.Text += $"{Environment.NewLine}Total running time: {timer.ElapsedMilliseconds / 1000} seconds";
}

Tip: Je kan polymorfisme en Inheritance gebruiken voor 2 methodes met een ander return type, indien deze return types hetzelfde base type gebruiken. Vraag me voor meer informatie!


Asynchrone methodes met hetzelfde return type die niet afhankelijk van elkaar zijn kunnen parallel naast elkaar uitgevoerd worden, i.p.v. dat elke operatie moet wachten tot de vorige voltooid is, wat de totale laadtijd van een operatie dramatisch kan inkorten. In dit geval is de totale laadtijd met 42% verminderd.

Tip: Asynchroon programmeren lijkt dus enkel voordelen te hebben. Is het een goed idee om alles asynchroon te maken? Nee, lang niet alle methodes in een applicatie hoeven asynchroon te zijn. Meestal wordt de code zo snel uitgevoerd dat de UI performance hits verwaarloosbaar zijn. Gebruik async voor long running operations zoals DB operaties. Alles asynchroon maken kan debuggen aanzienlijk moeilijker maken, zeker voor beginners, en kan de deuren openzetten voor ongewenste problemen zoals race conditions en lock issues. When in doubt -> KISS principe (Keep It Simple & Stupid).

Aangezien asynchrone operaties enkel door andere asynchrone operaties opgeroepen kunnen worden (behalve event handlers) zal dit je al een rode draad geven in het onderscheid te maken welke methodes async gemaakt moeten worden en welke sync kunnen blijven. Als later blijkt dat sommige methodes toch te lang in beslag nemen kunnen deze alsnog asynchroon gemaakt worden.