2008-11-27 17 views
5

Oto stosunkowo częste zadanie dla mnie i, myślę, dla wielu programistów .NET:
Chcę używać .NET ThreadPool do planowania wątków roboczych, które muszą przetwarzać dany typ zadania.Generic ThreadPool in .NET

Jako odświeżające, podpisy dla metody kolejkowania z puli wątków i towarzyszące jej delegata są:

public static bool QueueUserWorkItem (
    WaitCallback callBack, 
    Object state 
) 
public delegate void WaitCallback (Object state) 

Dlatego typowy rodzajowy klasy nić pracownik będzie wyglądać następująco:

public class Worker<T> { 
    public void schedule(T i_task) { 
     ThreadPool.QueueUserWorkItem(execute, i_task) 
    } 
    private void execute(Object o){ 
     T task = (T)o; //What happened to the type safety? 
     executeTask(task); 
    } 
    private void executeTask(T i_task){ 
     //process i_task 
    } 
} 

Zwróć uwagę na typ parametru state? To jest Object!

Jaki jest główny powód, dla którego zespół .NET zdecydował się nie generować metody QueueUserWorkItem (lub całej klasy ThreadPool)? Nie mogę uwierzyć, że po prostu to przeoczyli.

Oto jak chciałbym go zobaczyć:

//in the ThreadPool class: 
public static bool QueueUserWorkItem<T> (
    WaitCallback<T> callBack, 
    T state 
) 
public delegate void WaitCallback<T> (T state) 

To uczyniłoby klasa pracownik typu bezpieczny (i dużo jaśniejsze, IMHO):

public class Worker<T> { 
    public void schedule(T i_task) { 
     ThreadPool.QueueUserWorkItem<T>(execute, i_task) 
    } 
    private void execute(T i_task){ 
     //process i_task 
    } 
} 

I musi być brakuje coś.

Odpowiedz

5

Wygląda na to, że mówisz o kolejce pracy? (i brzmi jak clippy ...)

Dla rekordu, wątki puli wątków powinny być zwykle używane do krótkich kawałków pracy. Powinieneś idealnie stworzyć własne wątki dla długowiecznej kolejki. Zauważ, że .NET 4.0 może adoptować biblioteki CCR/TPL, więc dostaniemy trochę wbudowanych kolejek roboczych za darmo - ale nie jest trudno napisać wątkową kolejkę roboczą. I można zrobić to uniwersalne, zbyt ;-P

Re pytaniem - Wolę podejście przechwycony zmienne do przechodzenia w stan gwintów (BE one Thread, ThreadPool lub Control.Invoke):

Thread t = new Thread(() => SomeMethod(arg)); 
    t.IsBackground = true; 
    t.Name = "Worker n"; 
    t.Start(); 

daje to o wiele bardziej szczegółową kontrolę nad wątkiem, bez nasycania ThreadPool.

+2

Nie rozumiem Twojego argumentu nie używając puli wątków jako podstawową „realizacja” warstwą kolejce pracy. Czy jest to problem podczas używania * the *.NET ThreadPool ze względu na ograniczoną liczbę wątków? IMO naturalne jest założenie, że zadania w kolejce pracy są krótkie. Czy mógłbyś to rozwinąć? –

7

Skoro nie można spakować stanu, który ci się podoba, przekazując anonimowy delegat lub lambdę do wątku (poprzez przechwytywanie zmiennych), nie ma potrzeby generowania wersji ogólnej.

Na przykład, można napisać funkcję użytkową:

static void QueueItem<T>(Action<T> action, T state) 
{ 
    ThreadPool.QueueUserWorkItem(delegate { action(state); }); 
} 

Ale nie byłoby strasznie przydatne, jak można po prostu użyć delegata siebie w każdej chwili trzeba stan w zbiorczej zadania.

1

ThreadPool istnieje od .NET 1.1, który nie ma generics.

Lubię, jak wybrali, aby nie złamać kompatybilność wsteczną :-)

+5

Nie sądzę, że to jest poprawny argument. Wystarczy spojrzeć na wszystkie klasy kontenerów w wersji 1.1, które zostały "zaktualizowane", aby używać generycznych w wersji 2.0. Poza tym nie sugerowałem, aby * zastąpić * metodę kolejki ... jej ogólnym odpowiednikiem, ale dodać ogólną wersję obok. –