سؤال

أنا أبحث عن طريقة جيدة للتتبع (العد) التي فشل العمال عند قائمة الانتظار مع ThreadPool واستخدام Waithandle.waitall () لجميع المواضيع لإنهاء.

هل تشابك عداد تقنية جيدة أم أن هناك استراتيجية أكثر قوة؟

هل كانت مفيدة؟

المحلول

حسنًا ، إليك نهجًا يمكنك اتباعه. لقد قمت بتغليف البيانات التي نريد تتبعها في فصل 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الخيط ال thaving لإضافة الأرقام 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;
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top