\


 Monday, 03 May 2004
Znáte třídy ServicePoint a ServicePointManager? Měli byste...

Při používání více threadů například pro získání obsahu WWW stránek ze stejného URI nebo při asynchronním a současně prováděném volání více metod jedné WWW služby se můžete setkat s podivnými výjimkami nebo ještě podivnějšími prodlevami mezi jednotlivými voláními.
Za rovnoměrné využití síťových zdrojů je odpovědná třída ServicePointManager. Ta obhospodařuje kolekci objektů ServicePoint, které jsou vytvářeny při prvním požadavku na dané URI. Třída ServicePointManager má několik zajímavých vlastností a metod.
Vlastnost DefaultConnectionLimit - hodnota vlastnosti určuje, kolik konkurenčních připojení může ve stejném okamžiku přistupovat ke stejnému URI. V .Net Frameworku 1.1 jsou ve výchozím nastavení povolena dvě konkurenční připojení na stejné URI. Jestliže například z nějakého důvodu potřebujete asynchronně a "najednou" volat více metod WWW služby, měli byste ConnectionLimit zvýšit.
Vlastnost MaxServicePointIdleTime - tato vlastnost říká, jak dlouho musí být dané URI neaktivní, aby se stalo kořistí Garbage Collectoru. Neaktivní znamená, že s daným URI nebylo po zadanou dobu vytvořeno žádné spojení. Výchozí hodnotou je 900.000 milisekund (15 minut)
Vlastnost MaxServicePoints - tato vlastnost říká, kolik instancí ServicePoint může být vytvořeno. Jinými slovy, tato vlastnost omezuje počet URI, na které se lze v jednom okamžiku připojit. Ve výchozím nastavení žádný limit neexistuje (vlastnost obsahuje hodnotu 0).
Metoda FindServicePoint - přetížená metoda FindServicePoint vrátí objekt ServicePoint pro zadané URI. Když ServicePoint pro URI ještě neexistuje, tak metoda vytvoří a vrátí nový objekt ServicePoint, jinak je vrácen existující ServicePoint.

U třídy ServicePoint můžeme upravit vlastnosti, jež jsou po vytvoření objektu inicializovány výchozími hodnotami převzatými z třídy ServicePointManager.

ConnectionLimit - má stejný význam jako vlastnost DefaultConnectionLimit u ServicePointManageru.
MaxIdleTime = má stejný význam jako vlastnost DefaultConnectionLimit u ServicePointManageru.

Tak a teď jednoduchý demonstrační kód konzolové aplikace. Nejdříve kód, který změní DefaultConnectionLimit tak, aby odpovídal počtu požadavků (WebRequest). Vše proběhne relativně rychle a dle očekávání.

using System;
using System.Net;
using System.Threading;
namespace RStein.ServicePointManagerTester
{
  class ServicePointManagerTest
  {
    static void Main(string[] args)
    {
      Console.WriteLine(ServicePointManager.DefaultConnectionLimit);
       ServicePointManager.DefaultConnectionLimit = 4;
       WebRequest reg = WebRequest.Create("http://wwww.atlas.cz");
       WebRequest reg2 = WebRequest.Create("http://wwww.atlas.cz");
       WebRequest reg3 = WebRequest.Create("http://wwww.atlas.cz");
       WebRequest reg4 = WebRequest.Create("http://wwww.atlas.cz");
       WaitHandle handle0 = reg.BeginGetResponse(new AsyncCallback(test), reg).AsyncWaitHandle;
       WaitHandle handle1 = reg2.BeginGetResponse(new AsyncCallback(test), reg2).AsyncWaitHandle;
       WaitHandle handle2 =reg3.BeginGetResponse(new AsyncCallback(test), reg3).AsyncWaitHandle;
       WaitHandle handle3 =reg4.BeginGetResponse(new AsyncCallback(test), reg4).AsyncWaitHandle;
       WaitHandle.WaitAll(new WaitHandle[] {handle0, handle1, handle2, handle3});
       Console.WriteLine("vse");
       Console.Read();
     }

     private static void test(IAsyncResult ar)
     {
       Console.WriteLine("Konec requestu");
       try
       {
         WebRequest reg = (WebRequest)ar.AsyncState;         

        WebResponse response = reg.EndGetResponse(ar);         

        response.GetResponseStream().Close();       

     }
       catch(Exception e)
       {
         Console.WriteLine(e.ToString());
       }
     }
   }
}
Nyní změňte DefaultConnectionLimit na 1. Jak můžete pozorovat, vyřízení všech požadavků je citelně pomalejší (alespoň u mě na GPRS), protože jsou vyřizovány jeden po druhém. K URI "www.atlas.cz" může vždy přistoupit pouze jedno připojení. Mimochodem, víte proč se v MSDN neustále zdůrazňuje, že je třeba co nejdříve uzavřít všechny použité streamy? Jestliže ne, upravte řádku response.GetResponseStream() Close() ; na response.GetResponseStream(); a spusťte znovu aplikaci.



Monday, 03 May 2004 21:21:00 (Central Europe Standard Time, UTC+01:00)       
Comments [6]  .NET Framework