Frage

Ich suche nach einer guten Verfolgung (Zählen), die die Arbeiter in der Warteschlange mit einem Threadpool und mit WaitHandle fehlgeschlagen haben.

Ist ineinandergreifend ein Zähler eine gute Technik oder gibt es eine robustere Strategie?

War es hilfreich?

Lösung

Okay, hier ist ein Ansatz, den Sie wählen könnten. Ich habe die Daten, die wir in einer Klasse verfolgen möchten, eingekapselt TrackedWorkers. Es gibt einen Konstruktor in dieser Klasse, mit dem Sie festlegen können, wie viele Arbeitnehmer arbeiten werden. Dann werden die Arbeiter mithilfe von Mitarbeitern gestartet LaunchWorkers was einen Delegierten erfordert, der ein frisst object und kehrt eine zurück bool. Das object repräsentiert die Eingabe für den Arbeiter und die bool repräsentiert Erfolg oder Misserfolg, je nachdem true oder false Der Rückgabewert ist jeweils.

Im Grunde haben wir also ein Array, um den Arbeitnehmerstaat zu verfolgen. Wir starten die Arbeiter und setzen den Status, der diesem Arbeiter entspricht, abhängig vom Rückgabewert des Arbeiters. Wenn der Arbeiter zurückkehrt, setzen wir eine AutoResetEvent und WaitHandle.WaitAll für alle AutoResetEvents eingestellt werden.

Beachten Sie, dass es eine verschachtelte Klasse gibt, um die Arbeit (der Delegierte) zu verfolgen, den der Arbeiter tun soll, die Input für diese Arbeit und eine ID Wird verwendet, um den Status festzulegen AutoResetEvent entsprechend diesem Thread.

Beachten Sie sehr sorgfältig, dass wir nach Abschluss der Arbeit keinen Verweis auf den Arbeitsdelegierten haben func noch zu dem input. Dies ist wichtig, damit wir nicht versehentlich verhindern, dass Dinge Müll gesammelt werden.

Es gibt Methoden, um den Status eines bestimmten Arbeitnehmers sowie alle Indizes der Arbeitnehmer und alle Indizes der Arbeitnehmer, die fehlgeschlagen sind, zu erhalten.

Ein letzter Hinweis: Ich betrachte diese Codeproduktion nicht fürsfertig. Es ist nur eine Skizze des Ansatzes, den ich wählen würde. Sie müssen darauf achten, Tests, Ausnahmebehandlung und andere solche Details hinzuzufügen.

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

Stichprobenverbrauch:

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

    }
}

Das obige Programm wird vierundsechzig Themen starten. Das iDer Thread hat die Aufgabe, die Zahlen hinzuzufügen i und 2 * i und das Ergebnis in die Konsole drucken. Ich habe jedoch eine zufällige Menge Schlaf (weniger als eine Sekunde) hinzugefügt, um die Geschäftigkeit zu simulieren, und drehe eine Münze um, um den Erfolg oder Misserfolg des Fadens zu bestimmen. Diejenigen, die Erfolg haben, drucken die Summe, mit der sie beauftragt wurden, und kehrten zurück true. Diejenigen, die versagen, drucken nichts und kehren zurück false.

Hier habe ich verwendet

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;
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top