سؤال

أعتقد أنني قد تحتاج إلى إعادة التفكير في تصميمي.أواجه صعوبة في تضييق الخلل الذي يسبب جهاز الكمبيوتر الخاص بي لتعليق تماما ، وأحيانا رمي هرسولت 0 8007000 ه من فس 2010.

لدي تطبيق وحدة التحكم (الذي سأحوله لاحقا إلى خدمة) يتعامل مع نقل الملفات بناء على قائمة انتظار قاعدة البيانات.

أنا اختناق المواضيع المسموح بها لنقل.وذلك لأن بعض الأنظمة التي نتصل بها يمكن أن تحتوي فقط على عدد معين من الاتصالات من حسابات معينة.

على سبيل المثال ، يمكن للنظام أ قبول 3 اتصالات متزامنة فقط (مما يعني 3 سلاسل رسائل منفصلة).كل واحد من هذه المواضيع لديه كائن اتصال فريدة من نوعها ، لذلك يجب أن لا تعمل في أي مشاكل المزامنة لأنها لا تشارك اتصال.

نريد معالجة الملفات من تلك الأنظمة في دورات.لذلك ، على سبيل المثال ، سنسمح بـ 3 اتصالات يمكنها نقل ما يصل إلى 100 ملف لكل اتصال.هذا يعني أنه لنقل 1000 ملف من النظام أ ، يمكننا فقط معالجة 300 ملف لكل دورة ، حيث يسمح بـ 3 سلاسل رسائل مع 100 ملف لكل منها.لذلك ، على مدى عمر هذا النقل ، سيكون لدينا 10 خيوط.يمكننا فقط تشغيل 3 في وقت واحد.لذلك ، سيكون هناك 3 دورات ، وسوف تستخدم الدورة الأخيرة فقط 1 مؤشر ترابط لنقل آخر 100 ملف.(3 المواضيع س 100 الملفات = 300 الملفات في دورة)

العمارة الحالية حسب المثال هي:

  1. نظام.خيوط.الموقت يتحقق من قائمة الانتظار كل 5 ثوان عن شيء للقيام به عن طريق استدعاء جيتسشيدوليدتاسك()
  2. إذا لم يكن هناك شيء، جيتسشيدوليدتاسك () ببساطة لا يفعل شيئا
  3. إذا كان هناك عمل ، إنشاء مؤشر ترابط ثريادبول لمعالجة العمل [مؤشر ترابط العمل أ]
  4. مؤشر ترابط العمل يرى أن هناك 1000 ملف لنقلها
  5. مؤشر ترابط العمل (أ) يرى أنه لا يمكن أن يحتوي إلا على 3 مؤشرات ترابط تعمل على النظام الذي تحصل عليه من الملفات
  6. يبدأ مؤشر ترابط العمل أ ثلاثة مؤشرات ترابط عمل جديدة [ب ، ج ، د] والتحويلات
  7. موضوع العمل أ ينتظر ب ، ج ، د [WaitHandle.WaitAll(transfersArray)]
  8. مؤشر ترابط العمل يرى أنه لا يزال هناك المزيد من الملفات في قائمة الانتظار (يجب أن يكون 700 الآن)
  9. موضوع العمل يخلق مجموعة جديدة للانتظار على [transfersArray = new TransferArray[3] وهو الحد الأقصى للنظام أ ، ولكن يمكن أن يختلف على النظام
  10. يبدأ مؤشر ترابط العمل أ ثلاثة مؤشرات ترابط عمل جديدة [ب ، ج ، د] وينتظرها [WaitHandle.WaitAll(transfersArray)]
  11. تتكرر العملية حتى لا يكون هناك المزيد من الملفات لنقلها.
  12. مؤشر ترابط العمل أ يشير إلى أنه يتم

أنا باستخدام مانوالريسيتيفنت للتعامل مع الإشارات.

أسئلتي هي:

  1. هل هناك أي ظرف صارخ من شأنه أن يسبب تسرب الموارد أو المشكلة التي أواجهها?
  2. يجب أن حلقة من خلال مجموعة بعد كل WaitHandle.WaitAll(array) و اتصل array[index].Dispose()?
  3. عدد مقبض تحت إدارة المهام لهذه العملية تزحف ببطء
  4. أنا أدعو الإنشاء الأولي لموضوع العامل أ من نظام.خيوط.مؤقت.هل ستكون هناك أي مشاكل مع هذا?رمز لهذا الموقت هو:

(بعض كود الفصل للجدولة)

private ManualResetEvent _ResetEvent;

private void Start()
{
    _IsAlive = true;
    ManualResetEvent transferResetEvent = new ManualResetEvent(false);
    //Set the scheduler timer to 5 second intervals
    _ScheduledTasks = new Timer(new TimerCallback(ScheduledTasks_Tick), transferResetEvent, 200, 5000);
}

private void ScheduledTasks_Tick(object state)
{
    ManualResetEvent resetEvent = null;
    try
    {
        resetEvent = (ManualResetEvent)state;
        //Block timer until GetScheduledTasks() finishes
        _ScheduledTasks.Change(Timeout.Infinite, Timeout.Infinite);
        GetScheduledTasks();
    }
    finally
    {
        _ScheduledTasks.Change(5000, 5000);
        Console.WriteLine("{0} [Main] GetScheduledTasks() finished", DateTime.Now.ToString("MMddyy HH:mm:ss:fff"));
        resetEvent.Set();
    }
}


private void GetScheduledTask()
{
    try 
    { 
        //Check to see if the database connection is still up
        if (!_IsAlive)
        {
            //Handle
            _ConnectionLostNotification = true;
            return;
        }

        //Get scheduled records from the database
        ISchedulerTask task = null;

        using (DataTable dt = FastSql.ExecuteDataTable(
                _ConnectionString, "hidden for security", System.Data.CommandType.StoredProcedure,
                new List<FastSqlParam>() { new FastSqlParam(ParameterDirection.Input, SqlDbType.VarChar, "@ProcessMachineName", Environment.MachineName) })) //call to static class
        {
            if (dt != null)
            {
                if (dt.Rows.Count == 1)
                {  //Only 1 row is allowed
                    DataRow dr = dt.Rows[0];

                    //Get task information
                    TransferParam.TaskType taskType = (TransferParam.TaskType)Enum.Parse(typeof(TransferParam.TaskType), dr["TaskTypeId"].ToString());
                    task = ScheduledTaskFactory.CreateScheduledTask(taskType);

                    task.Description = dr["Description"].ToString();
                    task.IsEnabled = (bool)dr["IsEnabled"];
                    task.IsProcessing = (bool)dr["IsProcessing"];
                    task.IsManualLaunch = (bool)dr["IsManualLaunch"];
                    task.ProcessMachineName = dr["ProcessMachineName"].ToString();
                    task.NextRun = (DateTime)dr["NextRun"];
                    task.PostProcessNotification = (bool)dr["NotifyPostProcess"];
                    task.PreProcessNotification = (bool)dr["NotifyPreProcess"];
                    task.Priority = (TransferParam.Priority)Enum.Parse(typeof(TransferParam.SystemType), dr["PriorityId"].ToString());
                    task.SleepMinutes = (int)dr["SleepMinutes"];
                    task.ScheduleId = (int)dr["ScheduleId"];
                    task.CurrentRuns = (int)dr["CurrentRuns"];
                    task.TotalRuns = (int)dr["TotalRuns"];

                    SchedulerTask scheduledTask = new SchedulerTask(new ManualResetEvent(false), task);
                    //Queue up task to worker thread and start
                    ThreadPool.QueueUserWorkItem(new WaitCallback(this.ThreadProc), scheduledTask);     
                }
            }
        }

    }
    catch (Exception ex)
    {
        //Handle
    }
}

private void ThreadProc(object taskObject)
{
    SchedulerTask task = (SchedulerTask)taskObject;
    ScheduledTaskEngine engine = null;
    try
    {
        engine = SchedulerTaskEngineFactory.CreateTaskEngine(task.Task, _ConnectionString);
        engine.StartTask(task.Task);    
    }
    catch (Exception ex)
    {
        //Handle
    }
    finally
    {
        task.TaskResetEvent.Set();
        task.TaskResetEvent.Dispose();
    }
}
هل كانت مفيدة؟

المحلول 4

اتضح أن مصدر هذه المشكلة الغريبة لم يكن مرتبطا بالهندسة المعمارية بل بسبب تحويل الحل من 3.5 إلى 4.0.أنا إعادة إنشاء الحل ، وأداء أي تغييرات التعليمات البرمجية ، والمشكلة لم يحدث مرة أخرى.

نصائح أخرى

0 * 8007000 ه هو خطأ خارج الذاكرة.يبدو أن هذا وعدد المقبض يشير إلى تسرب الموارد.تأكد من أنك تتخلص من كل كائن ينفذ IDisposable.وهذا يشمل صفائف ManualResetEventالصورة التي تستخدمها.

إذا كان لديك الوقت ، قد تحتاج أيضا إلى تحويل إلى استخدام صافي 4.0 Task فئة;تم تصميمه للتعامل مع السيناريوهات المعقدة مثل هذا بشكل أكثر نظافة.عن طريق تعريف الطفل Task الكائنات ، يمكنك تقليل عدد الصفحات الإجمالي (المواضيع مكلفة للغاية ليس فقط بسبب الجدولة ولكن أيضا بسبب مساحة المكدس الخاصة بهم).

أنا أبحث عن إجابات لمشكلة مماثلة (مقابض العد زيادة مع مرور الوقت).

أخذت نظرة على بنية التطبيق الخاص بك ، وأود أن أقترح عليك شيئا يمكن أن تساعدك على الخروج:

هل سمعت عن إوكب (المدخلات منافذ الانتهاء الإخراج).

لست متأكدا من صعوبة تنفيذ هذا باستخدام ج # ولكن في ج / ج it إنها قطعة من الكعكة.باستخدام هذا يمكنك إنشاء تجمع مؤشر ترابط فريد (يتم تعريف عدد مؤشرات الترابط في هذا التجمع بشكل عام على أنه 2 س عدد المعالجات أو المعالجات النوى في جهاز الكمبيوتر أو الخادم) يمكنك ربط هذا التجمع إلى مقبض إوكب وتجمع يفعل العمل.انظر المساعدة لهذه الوظائف:كريتيوكومبليتيونبورت();بوستكويدكومبليتيونستاتوس();جيتكويدكومبليتيونستاتوس();

بشكل عام إنشاء والخروج المواضيع على الطاير يمكن أن يكون مضيعة للوقت ويؤدي إلى عقوبات الأداء وتجزئة الذاكرة.هناك الآلاف من الأدب حول إوكب في مسن وفي جوجل.

أعتقد أنه يجب عليك إعادة النظر في الهندسة المعمارية الخاصة بك تماما.حقيقة أنه يمكن أن يكون لديك فقط 3 اتصالات في وقت واحد هو التسول تقريبا لك لاستخدام 1 موضوع لتوليد قائمة الملفات و 3 المواضيع لمعالجتها.سوف مؤشر ترابط المنتج الخاص بك إدراج جميع الملفات في قائمة انتظار و 3 المواضيع المستهلك سوف ديكو ومواصلة المعالجة كما تصل العناصر في قائمة الانتظار.يمكن لقائمة انتظار الحظر تبسيط التعليمات البرمجية بشكل كبير.صافي 4.0 ثم يمكنك الاستفادة من بلوكينجكولكتيون صف دراسي.

public class Example
{
    private BlockingCollection<string> m_Queue = new BlockingCollection<string>();

    public void Start()
    {
        var threads = new Thread[] 
            { 
                new Thread(Producer), 
                new Thread(Consumer), 
                new Thread(Consumer), 
                new Thread(Consumer) 
            };
        foreach (Thread thread in threads)
        {
            thread.Start();
        }
    }

    private void Producer()
    {
        while (true)
        {
            Thread.Sleep(TimeSpan.FromSeconds(5));
            ScheduledTask task = GetScheduledTask();
            if (task != null)
            {
                foreach (string file in task.Files)
                {
                    m_Queue.Add(task);
                }
            }
        }
    }

    private void Consumer()
    {
        // Make a connection to the resource that is assigned to this thread only.
        while (true)
        {
            string file = m_Queue.Take();
            // Process the file.
        }
    }
}

لقد قمت بالتأكيد بتبسيط الأشياء في المثال أعلاه ، ولكن آمل أن تحصل على الفكرة العامة.لاحظ كيف أن هذا أبسط بكثير حيث لا يوجد الكثير في طريق مزامنة مؤشر الترابط (سيتم تضمين معظمها في قائمة انتظار الحظر) وبالطبع لا يوجد استخدام WaitHandle الأشياء.من الواضح أنه سيتعين عليك إضافة الآليات الصحيحة لإغلاق الخيوط بأمان ، ولكن يجب أن يكون ذلك سهلا إلى حد ما.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top