Domanda

Sto cercando un buon metodo di tracciamento (conteggio) che i lavoratori hanno fallito quando in coda con un ThreadPool e utilizzando WaitHandle.WaitAll () per tutte le discussioni alla fine.

E 'incastro un contatore di una tecnica buona o c'è una strategia più robusta?

È stato utile?

Soluzione

Ok, ecco un approccio che si potrebbe prendere. Ho incapsulato i dati che vogliamo tenere traccia in un TrackedWorkers di classe. C'è un costruttore su questa classe che consente di impostare il numero di lavoratori lavoreranno. Poi, gli operai vengono lanciati utilizzando LaunchWorkers che richiede un delegato che mangia un object e restituisce un bool. Il object rappresenta l'ingresso al lavoratore e il bool rappresenta successo o il fallimento seconda true o false essendo il valore di ritorno, rispettivamente.

Quindi, in pratica quello che facciamo abbiamo una matrice per tenere traccia dello stato operaio. Lanciamo lavoratori e impostare lo stato corrispondente a quello dei lavoratori a seconda del valore di ritorno da parte del lavoratore. Quando i rendimenti dei lavoratori, abbiamo fissato un AutoResetEvent e WaitHandle.WaitAll per tutta la AutoResetEvents da impostare.

Si noti che non v'è una classe annidata per tenere traccia del lavoro (il delegato) il lavoratore deve fare, l'ingresso che il lavoro, e di un ID utilizzato per impostare la AutoResetEvent status corrispondente a tale discussione.

Nota con molta attenzione che una volta che il lavoro è fatto non siamo in possesso di un riferimento al lavoro func delegato né alla input. Questo è importante in modo che non accidentalmente impediamo roba da essere garbage collection.

Ci sono metodi per ottenere lo stato di un determinato lavoratore, così come tutti gli indici dei lavoratori che si succedettero e tutti gli indici dei lavoratori che non è riuscita.

Un ultima nota: non considero questa produzione di codice pronto. Si tratta semplicemente di uno schizzo di un approccio che avrei preso. È necessario prendere cura di aggiungere test, gestione delle eccezioni e altri dettagli.

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

Utilizzo di esempio:

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

    }
}

Il programma di cui sopra sta per lanciare sessantaquattro discussioni. Il filo ith ha il compito di aggiungere il i numeri e 2 * i e stampare il risultato alla console. Tuttavia, ho aggiunto una quantità casuale di sonno (meno di un secondo) per simulare busyness e lancia una moneta per determinare il successo o il fallimento del filo. Coloro che riescono stampare la somma che avevano il compito di e true ritorno. Coloro che non riescono nulla di stampa e false ritorno.

Qui ho usato

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;
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top