Общий ThreadPool в .NET
-
11-07-2019 - |
Вопрос
Вот довольно распространенная задача для меня, и, как мне кажется, для многих программистов .NET:
Я хочу использовать .NET ThreadPool для планирования рабочих потоков, которые должны обрабатывать задачи определенного типа.
В качестве переподготовки подписи для метода очередей ThreadPool и связанного с ним делегата:
public static bool QueueUserWorkItem (
WaitCallback callBack,
Object state
)
public delegate void WaitCallback (Object state)
Следовательно, типичный типовой класс рабочего потока будет выглядеть примерно так:
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
}
}
Обратите внимание на тип параметра state
? Это Object
!
Какова убедительная причина того, что команда .NET решила не делать метод QueueUserWorkItem
(или весь класс ThreadPool
) универсальным? Я не могу поверить, что они просто упустили это из виду.
Вот как бы я хотел это увидеть:
//in the ThreadPool class:
public static bool QueueUserWorkItem<T> (
WaitCallback<T> callBack,
T state
)
public delegate void WaitCallback<T> (T state)
Это сделало бы рабочий класс безопасным для типов (и намного понятнее, ИМХО):
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
}
}
Должно быть, я что-то упустил.
Решение
Похоже, вы говорите о рабочей очереди? (и я звучу как клиппист ...)
Для записи, потоки пула потоков обычно должны использоваться для коротких частей работы. В идеале вы должны создать свои собственные потоки для долгоживущей очереди. Обратите внимание, что .NET 4.0 может принимать библиотеки CCR / TPL, поэтому мы бесплатно получим несколько встроенных рабочих очередей, но нетрудно написать потоковую рабочую очередь. И вы можете сделать его также общим ;-p
Ответьте на вопрос - я предпочитаю подход с захваченными переменными для передачи состояния в потоки (будь то Thread
, ThreadPool
или Control.Invoke
): р>
Thread t = new Thread(() => SomeMethod(arg));
t.IsBackground = true;
t.Name = "Worker n";
t.Start();
Это дает вам гораздо более детальный контроль над потоком, без насыщения ThreadPool
.
Другие советы
Поскольку легко упаковать любое желаемое состояние, передав анонимный делегат или лямбду в пул потоков (посредством захвата переменных), нет необходимости в универсальной версии.
Например, вы можете написать служебную функцию:
static void QueueItem<T>(Action<T> action, T state)
{
ThreadPool.QueueUserWorkItem(delegate { action(state); });
}
Но это было бы ужасно полезно, поскольку вы можете просто использовать делегата самостоятельно в любое время, когда вам нужно состояние в объединенной задаче.
ThreadPool существует с версии .NET 1.1, в которой не было универсальных элементов.
Мне нравится, как они решили не нарушать обратную совместимость: -)