Надежный метод отслеживания неудачных работников с Threadpool
-
25-09-2019 - |
Вопрос
Я ищу хороший метод отслеживания (подсчета). Какие работники не удались прийти к очереди с ThreadPool и используя WATHANDLE.WATALL () для всех потоков для завершения.
Блокируется счетчик хорошей техникой или есть ли более надежная стратегия?
Решение
Хорошо, вот подход, который вы могли бы взять. Я инкапсулировал данные, которые мы хотим отслеживать в классе TrackedWorkers
. Отказ На этом классе есть конструктор, который позволяет вам установить, сколько работников будет работать. Затем рабочие запускаются с использованием LaunchWorkers
который требует делегата, который ест object
и возвращает А. bool
. Отказ То object
представляет вход к работнику и bool
представляет успех или неудачу в зависимости от true
или false
Быть возвращающимся значением соответственно.
Так что в основном мы у нас есть массив для отслеживания работника. Мы запускаем рабочие и устанавливаем статус, соответствующий этому работнику в зависимости от возвращаемого значения от работника. Когда работник возвращается, мы устанавливаем AutoResetEvent
а также WaitHandle.WaitAll
для всех AutoResetEvents
быть установленным.
Обратите внимание, что существует вложенный класс для отслеживания работы (делегат), который должен делать работник, вход к этой работе и ID
используется для установки статуса AutoResetEvent
соответствует этой нити.
Очень внимательно отмечайте, что после выполнения работы мы не проводим ссылку на делегат работы func
ни к тому input
. Отказ Это важно, чтобы мы случайно не предотвращали вещи из мусора.
Существуют методы получения статуса конкретного работника, а также все индексы работников, которые преуспели и все индексы работников, которые провалились.
Последнее примечание: я не считаю этот изготовление кода готов. Это просто эскиз подхода, который я взял. Вам нужно позаботиться о добавлении тестирования, обработки исключений и других таких деталей.
class TrackedWorkers {
class WorkerState {
public object Input { get; private set; }
public int ID { get; private set; }
public Func<object, bool> Func { get; private set; }
public WorkerState(Func<object, bool> func, object input, int id) {
Func = func;
Input = input;
ID = id;
}
}
AutoResetEvent[] events;
bool[] statuses;
bool _workComplete;
int _number;
public TrackedWorkers(int number) {
if (number <= 0 || number > 64) {
throw new ArgumentOutOfRangeException(
"number",
"number must be positive and at most 64"
);
}
this._number = number;
events = new AutoResetEvent[number];
statuses = new bool[number];
_workComplete = false;
}
void Initialize() {
_workComplete = false;
for (int i = 0; i < _number; i++) {
events[i] = new AutoResetEvent(false);
statuses[i] = true;
}
}
void DoWork(object state) {
WorkerState ws = (WorkerState)state;
statuses[ws.ID] = ws.Func(ws.Input);
events[ws.ID].Set();
}
public void LaunchWorkers(Func<object, bool> func, object[] inputs) {
Initialize();
for (int i = 0; i < _number; i++) {
WorkerState ws = new WorkerState(func, inputs[i], i);
ThreadPool.QueueUserWorkItem(this.DoWork, ws);
}
WaitHandle.WaitAll(events);
_workComplete = true;
}
void ThrowIfWorkIsNotDone() {
if (!_workComplete) {
throw new InvalidOperationException("work not complete");
}
}
public bool GetWorkerStatus(int i) {
ThrowIfWorkIsNotDone();
return statuses[i];
}
public IEnumerable<int> SuccessfulWorkers {
get {
return WorkersWhere(b => b);
}
}
public IEnumerable<int> FailedWorkers {
get {
return WorkersWhere(b => !b);
}
}
IEnumerable<int> WorkersWhere(Predicate<bool> predicate) {
ThrowIfWorkIsNotDone();
for (int i = 0; i < _number; i++) {
if (predicate(statuses[i])) {
yield return i;
}
}
}
}
Использование образца:
class Program {
static Random rg = new Random();
static object lockObject = new object();
static void Main(string[] args) {
int count = 64;
Pair[] pairs = new Pair[count];
for(int i = 0; i < count; i++) {
pairs[i] = new Pair(i, 2 * i);
}
TrackedWorkers workers = new TrackedWorkers(count);
workers.LaunchWorkers(SleepAndAdd, pairs.Cast<object>().ToArray());
Console.WriteLine(
"Number successful: {0}",
workers.SuccessfulWorkers.Count()
);
Console.WriteLine(
"Number failed: {0}",
workers.FailedWorkers.Count()
);
}
static bool SleepAndAdd(object o) {
Pair pair = (Pair)o;
int timeout;
double d;
lock (lockObject) {
timeout = rg.Next(1000);
d = rg.NextDouble();
}
Thread.Sleep(timeout);
bool success = d < 0.5;
if (success) {
Console.WriteLine(pair.First + pair.Second);
}
return (success);
}
}
Вышеуказанная программа будет запущена шестьдесят четыре потока. То i
Тема имеет задачу добавления чисел i
а также 2 * i
и печатать результат к консоли. Однако я добавил случайное количество сна (менее одного секунды), чтобы имитировать жизненно возможностей, и я переворачиваю монету, чтобы определить успех или отказ нити. Те, которые преуспевают на распечатать сумму, с которыми они были поручены и вернуться true
. Отказ Те, которые терпят неудачу ничего и возвращают false
.
Здесь я использовал
struct Pair {
public int First { get; private set; }
public int Second { get; private set; }
public Pair(int first, int second) : this() {
this.First = first;
this.Second = second;
}
}