- każdy wątek domyślnie wykorzystuje około 1MB pamięci
- utworzenie nowego wątku wraz z organizacją pamięci dla niego trwa setki milisekund
Przed rozpoczęciem pracy z pulą wątków należy pamiętać, że będą one zawsze wątkami typu "background".
Dostęp do puli wątków można uzyskać na kilka sposobów:
Pula wątków poprzez Task Parallel Library (TPL)
TPL dostarcza specjalną klasę Task, która dostępna jest pod dwoma postaciami: generyczną i niegeneryczną. Wątek z Thread Pool można wystartować w poniższy sposób:
public static void Run() { Task.Factory.StartNew(NonGenericTask); } public static void NonGenericTask() { Console.WriteLine("This is thread from thread pool"); }
lub w sposób generyczny, gdzie możemy zwracać wartość z wątku.
public static void Run() { Task<string> downloader = Task.Factory.StartNew( () => GenericTask("http://www.wisla.krakow.pl")); Console.WriteLine("Some operations..."); var result = downloader.Result; Console.WriteLine(result); } public static string GenericTask(string uri) { Console.WriteLine("This is thread from thread pool"); using (var wc = new System.Net.WebClient()) return wc.DownloadString(uri); }
Warto pamiętać, że w momencie, gdy odwołujemy się do property Result, wątek główny zostanie zawieszony do momentu wywołania wątku z puli.
TPL został wprowadzony w .NET 4.0. W starszych wersjach zachodzi konieczność korzystania z puli wątków w nieco inny sposób.
Pula wątków poprzez klasę ThreadPool
Tutaj mamy do dyspozycji klasę ThreadPool, gdzie wywołując wątek możemy przez parametr podać stan (jako typ object).
public static void Run() { Console.WriteLine("Without TPL"); ThreadPool.QueueUserWorkItem(QueueUserWorkItemFcn, DateTime.Today.ToShortDateString()); } public static void QueueUserWorkItemFcn(object dateTime) { Console.WriteLine("This is thread from thread pool, at {0}", dateTime); }
Jeżeli chcemy zwracać obiekty z wątku nie używając TPL, należy wykorzystać tzw. asynchronous delegates.
public static void Run() { Console.WriteLine("Asynchronous delegate"); Func<string, string> func = new Func<string, string>(AsynchronousDelegate); IAsyncResult value = func.BeginInvoke("this is some text", null, null); Console.WriteLine("Some operations..."); var str = func.EndInvoke(value); Console.WriteLine(str); } public static string AsynchronousDelegate(string letters) { Console.WriteLine("This is thread from thread pool"); IEnumerable<char> rev = letters.Reverse(); string result = ""; foreach (var @char in rev) { result += @char; } return result; }
Operacja EndInvoke czeka aż asynchroniczny delegat wykona swoje zadanie, zawieszając główny wątek, odbiera rezultat przetwarzania, a także "przerzuca" wyjątek z wątku w tle do wątku głównego.
Wywołując BeginInvoke można jako drugi parametr przekazać callback, który wykona się po zakończeniu pracy wątku. Callback jako parametr przyjmuje typ IAsyncResult.
public static void Run() { var method = new Func<string, string>(AsynchronousDelegate); method.BeginInvoke("My text", Callback, method); } public static void Callback(IAsyncResult result) { var target = (Func<string, string>)result.AsyncState; string res = target.EndInvoke(result); Console.WriteLine(res); }
Brak komentarzy:
Prześlij komentarz