2008-11-27 27 views
5

Hier ist eine relativ häufige Aufgabe für mich, und ich denke, für viele. NET-Programmierer: Ich möchte mit dem .NET ThreadPool für die Planung von Worker-Threads, die einen bestimmten Typ von verarbeiten müssen Aufgaben.Generic ThreadPool in. NET

als Auffrischung, sind die Unterschriften für die Warteschlangenverfahren des Threadpools und die damit verbunden Delegierten:

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

:

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

Daher ist eine typische Klasse generic Worker-Thread etwas aussehen würde, Beachten Sie den Typ des state Parameters? Es ist Object!

Was ist der zwingende Grund, warum das .NET-Team entschied, die QueueUserWorkItem-Methode (oder die gesamte ThreadPool-Klasse) generisch zu machen? Ich kann nicht glauben, dass sie es einfach übersehen haben.

Hier ist, wie ich möchte es sehen:

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

dies der Arbeiter Klasse typsicher machen würde (und viel klarer, 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 fehlen darf etwas.

Antwort

5

Es klingt, als würden Sie über eine Arbeitswarteschlange sprechen? (und ich höre wie klippig ...)

Für den Datensatz sollten Thread-Pool-Threads in der Regel für kurze Arbeiten verwendet werden. Sie sollten idealerweise Ihre eigenen Threads für eine langlebige Warteschlange erstellen. Beachten Sie, dass .NET 4.0 möglicherweise die CCR/TPL-Bibliotheken übernimmt, sodass wir einige eingebaute Arbeitswarteschlangen kostenlos erhalten - aber es ist nicht schwer, eine Arbeitswarteschlange mit Threads zu schreiben. Und Sie können es generische machen, auch ;-p

Zur Frage - ich bevorzuge die erfassten Variablen Ansatz Zustand in Threads vorbei (seien sie Thread, ThreadPool oder Control.Invoke):

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

Dies gibt Sie haben eine viel feinere Kontrolle über den Faden, ohne die ThreadPool zu sättigen.

+2

Ich verstehe nicht, Ihr Argument keinen Thread-Pool als Underlying Execution Schicht einer Arbeitswarteschlange verwenden. Ist das ein Problem bei der Verwendung von * the *?NET ThreadPool Klasse aufgrund der begrenzten Anzahl von Threads dort? Es ist normal anzunehmen, dass Aufgaben in einer Arbeitswarteschlange kurz sind. Kannst du bitte etwas ausarbeiten? –

7

Da es einfach ist, einen beliebigen Status zu verpacken, indem ein anonymer Delegat oder Lambda an den Threadpool übergeben wird (durch Variablenerfassung), ist keine generische Version erforderlich.

Zum Beispiel könnten Sie eine Nutzenfunktion schreiben:

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

Aber es wäre nicht sehr nützlich sein, da man einfach einen Delegaten selbst jederzeit Sie brauchen Zustand in der gepoolten Aufgabe verwenden kann.

1

ThreadPool existiert seit .NET 1.1, die keine Generics hatte.

Ich mag, wie sie wollten, nicht brechen Abwärtskompatibilität :-)

+5

Ich denke nicht, dass dies ein gültiges Argument ist. Sehen Sie sich einfach alle Container-Klassen in 1.1 an, die für die Verwendung von Generics in 2.0 "aufgerüstet" wurden. Außerdem habe ich nicht vorgeschlagen, die Queue-Methode mit ihrem generischen Gegenstück zu ersetzen, sondern die generische Version hinzuzufügen. –