2008-11-27 18 views
5

He aquí una tarea relativamente común para mí, y creo que para muchos programadores de .NET:
Quiero utilizar .NET ThreadPool para programar subprocesos de trabajo que necesitan procesar un tipo determinado de Tareas.Generic ThreadPool en .NET

A modo de recordatorio, las firmas para el método de puesta en cola de ThreadPool y su delegado asociado son:

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

Por lo tanto, una clase subproceso de trabajo genérico típico sería algo como:

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 
    } 
} 

Observe el tipo del parámetro state? ¡Es Object!

¿Cuál es la razón de peso por la cual el equipo de .NET eligió no hacer que el método QueueUserWorkItem (o la clase completa ThreadPool) sea genérico? No puedo creer que simplemente lo hayan pasado por alto.

Así es como me gustaría verlo:

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

Esto haría que la clase trabajadora de tipo seguro (y mucho más claro, en mi humilde opinión):

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 
    } 
} 

Debo estar perdiendo alguna cosa.

Respuesta

5

Parece que está hablando de una cola de trabajo? (y sueno como clippy ...)

Para el registro, los subprocesos de grupo de subprocesos normalmente se deben utilizar para los trabajos cortos. Lo ideal sería crear sus propios hilos para una cola de larga duración. Tenga en cuenta que .NET 4.0 puede estar adoptando las bibliotecas CCR/TPL, por lo que obtendremos algunas colas de trabajo incorporadas de forma gratuita, pero no es difícil escribir una cola de trabajo enhebrada. Y puede que sea genérica, también ;-P

la cuestión Re - Yo prefiero el enfoque de variables capturado al pasar del estado en hilos (ya sean Thread, ThreadPool o Control.Invoke):

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

Esto da tienes mucho más control granular sobre el hilo, sin saturar el ThreadPool.

+2

No entiendo el argumento de no utilizar un grupo de subprocesos como la capa subyacente de 'ejecución' de una cola de trabajo. ¿Es esto un problema cuando se usa * the *.NET clase ThreadPool debido a la cantidad limitada de subprocesos allí? OMI es natural suponer que las tareas en una cola de trabajo son cortas. ¿Puedes por favor elaborar? –

7

Dado que es trivial empaquetar cualquier estado que desee pasando un delegado anónimo o lambda al grupo de subprocesos (a través de la captura de variables), no hay necesidad de una versión genérica.

Por ejemplo, podría escribir una función de utilidad:

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

Pero no sería terriblemente útil, ya que simplemente puede utilizar un delegado a sí mismo cada vez que necesite Estado en la tarea conjunta.

1

ThreadPool existe desde .NET 1.1 que no tenía genéricos.

me gusta la forma en que decidieron no romper la compatibilidad hacia atrás :-)

+5

No creo que este sea un argumento válido. Solo mire todas las clases de contenedor en 1.1 que se "actualizaron" para usar genéricos en 2.0. Además, no estaba sugiriendo * reemplazar * el método Queue ... con su homólogo genérico, sino agregar la versión genérica junto a él. –