Dajbych.net


ASP.NET Web User Control a jeho paralelní zpracování

, 2 minuty čtení

net2010 logo

Programujeme-li Web User Control jehož úkolem je jen stáhnout informaci z jiného webu, zpracovat jí a vrátit patřičný HTML kód, není to nic světoborného. Stránka obsahující onen ovládací prvek se jen poprvé načítá o něco déle, další požadavky jsou už vyřízeny rychle díky ASP.NET Caching, nebo díky implementaci návrhového vzoru Proxy. Pokud ovšem máme ovládacích prvků na stránce dvacet a každý z nich potřebuje stáhnout něco jiného, situace se začíná poněkud dramatizovat.

V samotném generování HTTP odpovědi ASP.NET Enginem žádný paralelismus není. Ten se využívá na zpracování více HTTP požadavků současně. Jednotlivé ovládací prvky jsou postupně generovány jeden po druhém. Pokud trvá generování jednoho ovládacího prvku 0,7 sekundy, pak stránka obsahující dvacet takových prvků se bude načítat 14 sekund. Generování reportů, nebo volání pomalých webových služeb se tak může velmi znepříjemnit.

V některých případech charakteristika dat a četnost jejich čtení umožňuje externí obsah stáhnout v proceduře Application_Start a ovládací prvek ho jen vyzvedne. Pak se ale vytratí krása ovládacího prvku, která spočívá v tom, že jeho obsah definujeme pomocí parametrů. Pokud se bude každá hodnota parametru někam registrovat, aby se obsah načetl už při startu aplikace, může se stát, že se ztratí přehled o tom, který obsah je v jaké stránce využit. Navíc bude aplikace při startu načítat hodně dat, což je nepříjemné hlavně během jejího vývoje.

Pro paralelní zpracování ovládacích prvků na stránce je v ASP.NET technologie Asynchronous Web Parts. Bez jejího využití by ovládací prvek vypadal nějak takto:

public partial class WebUserControl : System.Web.UI.UserControl {

    Thread thread;
    string result;
    
    protected override void OnInit(EventArgs e) {
        thread = new Thread(new ThreadStart(HardWork));
        thread.Priority = ThreadPriority.AboveNormal;
        thread.Start();
    }

    private void HardWork() {
        for (int suma = 0; suma < 7; suma++) Thread.Sleep(100);
        result = "výsledek";
    }

    protected override void Render(HtmlTextWriter writer) {
        thread.Join();
        writer.Write(string.Format("<strong>{0}</strong>", result));
    }
    
}

Pokud začneme v ovládacím prvku něco dělat v jiném vlákně, musí být práce hotova v proceduře Render. Začít něco vykonávat má smysl v proceduře OnInit, kdy už jsou nastaveny vlastnosti ovládacího prvku. ASP.NET nám v procedurách OnInit sekvenčně spustí všechna vlákna. Procedury se ukončí, takže se pokračuje dál s prací na stránce až konečně v proceduře Render pomocí Join() čekáme, než se všechna vlákna dokončí.

Asynchronous Web Parts se používá obdobně. Ovládací prvek musí implementovat rozhraní IAsyncResult a stránka, jejíž ovládací prvky se mají generovat paralelně, musí obsahovat parametr Async="true".