Pregunta

Estoy buscando un buen método de seguimiento (contado) que los trabajadores han fallado cuando se pusieron en cola con un threadpool y usando waithandle.waitall () para que todos los hilos terminen.

¿Es el enclavamiento de un mostrador una buena técnica o hay una estrategia más robusta?

¿Fue útil?

Solución

Bien, aquí hay un enfoque que podrías adoptar. He encapsulado los datos que queremos rastrear en una clase TrackedWorkers. Hay un constructor en esta clase que le permite establecer cuántos trabajadores trabajarán. Luego, los trabajadores se lanzan utilizando LaunchWorkers que requiere un delegado que come un object y devuelve un bool. los object representa la entrada al trabajador y al bool representa el éxito o el fracaso dependiendo de true o false Ser el valor de retorno, respectivamente.

Así que básicamente lo que hacemos tenemos una matriz para rastrear el estado de los trabajadores. Lanzamos a los trabajadores y establecemos el estado correspondiente a ese trabajador dependiendo del valor de devolución del trabajador. Cuando el trabajador regresa, establecemos un AutoResetEvent y WaitHandle.WaitAll por todo el AutoResetEvents para ajustar.

Tenga en cuenta que hay una clase anidada para rastrear el trabajo (el delegado) que se supone que debe hacer el trabajador, la entrada a ese trabajo y un ID Se usa para establecer el estado AutoResetEvent correspondiente a ese hilo.

Tenga en cuenta con mucho cuidado que una vez que se realiza el trabajo, no tenemos una referencia al delegado del trabajo func ni al input. Esto es importante para que no evitemos accidentalmente que las cosas sean recolectadas de basura.

Existen métodos para obtener el estado de un trabajador en particular, así como todos los índices de los trabajadores que tuvieron éxito y todos los índices de los trabajadores que fallaron.

Una última nota: no considero esta producción de código lista. Es simplemente un boceto del enfoque que tomaría. Debe tener cuidado de agregar pruebas, manejo de excepciones y otros detalles similares.

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

Uso de la muestra:

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);

    }
}

El programa anterior va a lanzar sesenta y cuatro hilos. los iEl hilo tiene la tarea de agregar los números i y 2 * i e imprimir el resultado en la consola. Sin embargo, he agregado una cantidad aleatoria de sueño (menos de un segundo) para simular el ajetreo y volteo una moneda para determinar el éxito o el fracaso del hilo. Aquellos que tienen éxito imprimen la suma que se les encargó y regresó true. Los que no fallan en nada y regresan false.

Aquí he usado

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;
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top