ASPNL logo (1 kb)
zaterdag 17 mei 2008




Microsoft MVP

.NET Codewise Community
<< vorige | overzicht | volgende >>

Threading demo

Door Rutger Smit
19 september 2004

Demo ontwikkeld voor ASPNL.com in Visual Studio.NET 2003. Code geschreven in C# en gebaseerd op het .NET Framework versie 1.1.

Inleiding

Dit artikel gaat over een geweldige nieuwe mogelijkheid die het .NET Framework ons biedt voor ASP.NET applicaties: Threading. In de demo pagina’s die bij dit artikel horen gaan we zien dat langdurige processen zonder heel veel moeite gestart kunnen worden vanaf een pagina zonder dat de bezoeker van die pagina op respons van de webserver hoeft te wachten.

Wat is een Thread?

Applicaties worden uitgevoerd door een proces. Een proces is een entiteit binnen het systeem dat z'n eigen systeembronnen heeft, en tijd krijgt om een applicatie uit te voeren. Een proces is geheel gescheiden van andere processen in het systeem, zodat meerdere applicatie tegelijk uitgevoerd kunnen worden. Code in een applicatie wordt uitgevoerd door een thread, en elk proces bevat dan ook minimaal één thread. Applicaties die maar één thread gebruiken noemen we single-threaded. ASP.NET is echter multi-threaded, want als er maar één thread zou zijn, dan zouden alle requests één-voor-één uitgevoerd moeten worden, en zou een pagina die heel kort duurt moeten wachten totdat alle voorgaande pagina's klaar zijn. Om dat te voorkomen heeft ASP.NET een zogenaamde thread-pool (een verzameling threads die gebruikt kunnen worden om een request af te handelen). Wanneer een request gemaakt wordt, gebruikt ASP.NET een van de threads in de thread-pool om een pagina uit te voeren. Een pagina wordt normaal gezien dus door één thread uitgevoerd en is daarom normaal gezien single-threaded.

Multi-threading in ASP.NET

Omdat een ASP.NET pagina single-threaded is hebben we een probleempje als het gaat om het uitvoeren van langdurige operaties. Een operatie die op de server enkele secondes duurt laat de client (de bezoeker van de website) al die tijd wachten. Daar komt nog eens de tijd van het versturen van de output van server naar client bij plus de tijd die de browser nodig heeft om de html te parsen tot een zichtbare pagina. Op het moment dat je bepaalde logica wilt uitvoeren die meer tijd in beslag neemt, bijvoorbeeld meer dan 10 seconden, zal de client al die tijd wachten op een antwoord van de server. In de meeste gevallen zal er na 90 seconden een server timeout plaats vinden. Echter, de meeste mensen zijn na 20 seconden het wachten al zat en sluiten hun venster of klikken op Refresh waardoor de code nogmaals uitgevoerd wordt.

In classic asp had je dan een probleem. Meestal werd er omheen gehacked door het in batches uit te voeren, de Script.TimeOut extreem hoog te zetten en/of de pagina te tweaken met Response.Buffer/Response.Flush. Gelukkig kunnen we in ASP.NET gebruik maken van Threading, en kunnen we een operatie laten uitvoeren door een andere thread dan de thread die de pagina zelf uitvoert. Hierdoor kan de thread die de pagina uitvoert gewoon verder.

Hoe het werkt

Ok, hands on! Hieronder volgt een bespreking van de code die ik voor deze demo geschreven heb. Het proces dat bij mij veel tijd in beslag neemt is Thread.Sleep (5000); dit geeft het zelfde effect als een immense loop door records of een andere operatie dat veel tijd in beslag neemt. Wil je de code van deze demo toepassen op je eigen ASP.NET pagina dan hoef je op de plaats waar ik Thread.Sleep (5000); heb staan alleen maar je eigen code te plaatsen.

In de demo zitten de volgende pagina’s waarvan de werking hieronder uitgelegd wordt:

    Default.aspx(.cs)
    Openingspagina met een link naar de pagina zonder threading en een link naar een pagina die hetzelfde doet maar dan met threading. Tevens nog een link naar een zip file met daarin de code en dit PDF document.

    ZonderThreading.aspx(.cs)
    Pagina met de code voor het uitvoeren van een langdurige operatie zonder threading.

    MetThreading.aspx(.cs)
    Pagina met de code voor het uitvoeren van een langdurige operatie met threading.

    Polling.aspx(.cs)
    Deze pagina wordt in MetThreading.aspx gebruikt om te bewijzen dat de code van MetThreading.aspx daadwerkelijk functioneert.

ZonderThreading.aspx(.cs)

    Allereerst moeten we de namespace System.Threading importeren om later een langdurige operatie te kunnen simuleren. In een pagina met een langdurig proces maar zonder threading is deze dus niet nodig! In void Button1_Click schrijven we eerst wat informatie naar een TextBox (LogTextBox) om inzicht te krijgen in de tijd die bepaalde acties in de code in beslag neemt. Tussen deze twee tijden voeren we de method StartProces() uit. Dit is in deze demo het process dat veel tijd in beslag zal gaan nemen. In StartProces() voeren we Thread.Sleep(5000) uit om het langdurige proces te simuleren. Op deze plaats kun je eigen code plaatsen die veel tijd in beslag neemt.

    Als je deze pagina in je browser bekijkt en op de button klikt wordt de code uitgevoerd. In de textbox zul je twee tijden zien staan, de tijd voordat de operatie gestart werd en de tijd dat de operatie klaar was. In de demo zal het verschil 5 seconden zijn (5000 milliseconden).

MetThreading.aspx(.cs)

    Ook in dit bestand moeten we System.Threading importeren, en ditmaal niet alleen om een langdurige operatie te simuleren maar ook om een nieuwe thread op te starten. Net als in ZonderThreading.aspx schrijven we eerst wat informatie naar een textbox voordat we het langdurige proces opstarten. Vervolgens maken we een nieuwe thread aan en starten deze:

    ThreadStart entry = new ThreadStart(StartProces) ;
    Thread thread = new Thread(entry);
    thread.Priority= ThreadPriority.Lowest;
    thread.Start();

    Let hierbij op dat StartProces zonder () geschreven wordt! Omdat deze thread op de achtergrond draait en we de website niet willen vertragen zetten we de priority op ThreadPriority.Lowest. Aan het einde van de method StartProces() schrijven we de huidige tijd naar het Cache object, deze wordt in polling.aspx weer opgevraagd om te kunnen laten zien dat de operatie afgerond is (zie hieronder bij het bespreken van polling.aspx). Let op: omdat het een separate thread is kunnen we geen gebruik maken van objecten die in een andere scope draaien zoals Session, Request en Response.

Polling.aspx(.cs)
Dit bestand wordt in een Iframe in MetThreading.aspx geladen. De pagina heeft een Refresh van 2 seconden om de status van de langdurige operatie te controleren. In de Page_Load event van dit bestand wordt de inhoud van Cache["ProcessEnd"] naar een label geschreven. In situaties waar we threading meestal gebruiken komen er geen user interface zaken aan de orde, maar in deze demo is het handig om op een simpele manier te laten zien dat een thread op de achtergrond door draait.

Overige bestanden
De overige bestanden worden standaard door Visual Studio.NET aangemaakt en hebben geen directe relatie met de code uit deze demo.

Conclusie

Door gebruik te maken van threading kunnen we code die veel tijd in beslag neemt om uitgevoerd te worden op een slimme manier afhandelen zonder daarbij het geduld van de client op de proef te stellen. Het is daarom een zeer bruikbare mogelijkheid die het .NET Framework ons biedt.

<< vorige | ^ naar boven | overzicht | volgende >>
copyright 2000-2007 ASPNL